From 50e32cef2f5a45be81f02d907861a12748a988c7 Mon Sep 17 00:00:00 2001 From: "Dott. Federico Volpini" <federico.volpini@isti.cnr.it> Date: Thu, 23 May 2013 11:05:40 +0000 Subject: [PATCH] More synthetic output. Added warnings rather than only errors. Caseless comparison for class and property names. --- .../transformations/validateOntUML.m2t | 224 +++++++++++------- 1 file changed, 135 insertions(+), 89 deletions(-) diff --git a/transformations/org.universaal.tools.transformationcommand/transformations/validateOntUML.m2t b/transformations/org.universaal.tools.transformationcommand/transformations/validateOntUML.m2t index d5a51be14..c7ee98d72 100644 --- a/transformations/org.universaal.tools.transformationcommand/transformations/validateOntUML.m2t +++ b/transformations/org.universaal.tools.transformationcommand/transformations/validateOntUML.m2t @@ -5,93 +5,109 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. var ClassHashtable:hashtable var datatypeImportMap:hashtable var errorsList:list + var errors:integer = 0 + var warnings:integer = 0 var debugEnabled:boolean = false var logEnabled:boolean = true var generalEntityTree:hashtable - var listOfUpperOntologyEntities:hashtable + var listOfUpperOntology:hashtable uml.Model::main() { // Init - verbose("Initializing...", false, true) + verbose("----\nStart validation of UML ontology model "+self.name+"\n----\n",false,true) + verbose("Initializing\n", false, true) if (self.hasStereotype("owlOntology")) { - verbose("The owlOntology stereotype should NOW be applied to the root package(s).\nRemember to set all required values (defaultnamespace and name) for each package!",true,true) + verbose("* The owlOntology stereotype should NOW be applied to the root package(s).\nRemember to set all required values (defaultnamespace and name) for each package!\n",true,true) } // Create the list of upper ontology entities self.createSuperentitiesList() self.initDatatypeImportMap() - if(listOfUpperOntologyEntities.size() == 0){ - verbose("No upper ontology defined!!",true,false) + if(listOfUpperOntology.size() == 0){ + verbose("* No upper ontology defined!!\n",true,false) } else { self.ownedMember -> forEach( p:uml.Package ) { - verbose("Start Processing Model Packages...", false, true) + verbose("Start Processing Model Packages\n", false, true) if (!p.hasStereotype("owlOntology")) { - verbose("The package " + p.name + " is not stereotyped with owlOntology!\nIt is required to set the owlOntology stereotype on ALL root packages.",true,true) - } else { - p.processOntologyPackage() + verbose("* The package " + p.name + " is not stereotyped with owlOntology!\nIt is required to set the owlOntology stereotype on ALL root packages.\n",true,true) } + p.processOntologyPackage() } } + verbose("----\nCheck Report:\n",false,true) + if(!errorsList.isEmpty()) { - verbose("*** ERRORS OCCURRED WHILE CHECKING ***",false,true) + verbose(errorsList.size()+" problem(s) occurred when validating UML ontology model #"+self.name+"\n----\n",false,true) if(!debugEnabled){ errorsList->forEach(e){ verbose(e,false,true); } } } else { - verbose("\n\n--- EVERYTHING'S OK ---",false,false) + verbose("EVERYTHING'S OK!\n----\n",false,false) + } + } + + uml.Package::checkErrors(){ + if(errors > 0 || warnings > 0){ + verbose(" "+errors+" error(s), "+warnings+" warning(s)!\n",false,true) + } else { + verbose(" OK!\n",false,true) } + + errors = 0 + warnings = 0 } uml.Package::processOntologyPackage() { // Creates the Model Entity List - verbose("Building Model Class list and tree",false,true) + verbose("Building Model Class list and tree...",false,true) self.ownedElement->forEach(c : uml.Class) { c.name = c.name.trim() EntityList.add(c) - c.updategeneralEntityTreeHashtable() + c.updateGeneralEntityTreeHashtable() } - verbose("Start checking...",false,true) + self.checkErrors() + + verbose("Checking for unnamed entities or entities whith the same name... ",false,true) + // Check for empty Entity names or duplicate entry if(self.checkEmpty(EntityList) && self.checkUnity(EntityList)){ - - + verbose("OK!!\n",false,true) + // If everything's ok continue.. EntityList->forEach(entity : uml.Class) { - entity.name = entity.name.trim() - - verbose("Start "+entity.name+" analisys...",false,false) + verbose("Class "+entity.name+"...",false,true) // 1. Class generalization Check - verbose("Checking for right generalization of "+entity.name,false,false) - entity.checkRightgeneralEntityTreeization(entity.name) + verbose("\nChecking for right generalization of "+entity.name+"...\n",false,false) + entity.checkRightGeneralization(entity.name) - // 2. Creates the Property List for each class + verbose("\nChecking for right naming conventions of "+entity.name+"...\n",false,false) + entity.checkNamingConventions() + + // 2. Creates the Property List for each class // checking for no empty props or undefined props types PropertyList = entity.getPropertyList() + self.checkEmpty(PropertyList) + self.checkUnity(PropertyList) + + PropertyList->forEach(p:uml.Property){ + p.checkNamingConventions() + } - // 2.1 look for dupicate entry for props - if(self.checkUnity(PropertyList) /*&& errorsList.isEmpty()*/){ - //entity.updateHashtableClass(PropertyList) - - verbose("Checking for right Naming conventions for "+entity.name,false,false) - // 3. Check naming conventions for classes and properties - entity.checkNamingConventions() - PropertyList->forEach(p:uml.Property){ - p.checkNamingConventions() - } - } + self.checkErrors() } - } + } else verbose("\nThe control can not continue because of fatal errors\n",false,true) + } - uml.Element::checkNamingConventions(){ + uml.Classifier::checkNamingConventions(){ var elementProps:hashtable = self.getElementProps() var name:string = elementProps.get('name') var type:string = elementProps.get('type') @@ -99,49 +115,62 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. if(self.allowedCharlist()){ - if(type=='Class'){ - if(!name.isUpperCase(0)){ - verbose (parent+name+": First character should be Uppercase",true,false) - } - } else { - if(name.isUpperCase(0)){ - verbose (parent+name+": First character should be lowercase",true,false) + if(name.size()>0){ + if(type=='Class'){ + if(!name.isUpperCase(0)){ + verbose ("!"+parent+name+": First character's name should be Uppercase\n",true,false) + } + } else { + if(name.isUpperCase(0)){ + verbose ("!"+parent+name+": First character's name should be lowercase\n",true,false) + } } } - } else verbose (parent+name+": No valid characters in name",true,false); + } else verbose ("*"+parent+name+": No valid characters in name\n",true,false); } - uml.Class::updategeneralEntityTreeHashtable() { + uml.Class::updateGeneralEntityTreeHashtable() { if(self.general.size() > 0){ - if(self.general.size() > 1) verbose(self.name + ": Multiple superclasses found. Use interfaces instead - additional superclasses are igonered!",true,false) + if(self.general.size() > 1) verbose("!"+self.name + ": Multiple superclasses found. Use interfaces instead - additional superclasses are igonered!\n",true,false) generalEntityTree.put(self.name, self.general.first()) // key: derived class name, value: parent class } } - uml.Class::checkRightgeneralEntityTreeization(name:string) { - var parent:uml.Class = generalEntityTree.get(self.name) - if(parent != null){ + uml.Class::checkRightGeneralization(name:string) { + var ontKeys:list = listOfUpperOntology.keys() + ontKeys->forEach(ontName){ + var listOfUpperOntologyEntities:hashtable = listOfUpperOntology.get(ontName) + if(listOfUpperOntologyEntities.get(name) != null){ + verbose("!"+self.name+": the same name has already been defined in the upper ontology #"+ontName,true,false) + return + } + } + var parent:uml.Class = generalEntityTree.get(self.name) + if(parent != null){ verbose(self.name+"->"+parent.name,false,false) if(parent.name.equals(name)){ - verbose(name+": circular derivation found!",true,false) + verbose("*"+name+": circular derivation found!\n",true,false) return } - if(self.checkIfFinal()) verbose(self.name+": Cannot have parent class!!",true,false) - else parent.checkRightgeneralEntityTreeization(name) + if(self.checkIfFinal()) verbose("*"+self.name+": Cannot have parent class!!\n",true,false) + else parent.checkRightGeneralization(name) } else { - if (self.checkIfFinal()) verbose("OK!!",false,false) + if (self.checkIfFinal()) verbose("OK!!\n",false,false) else { - var superEntities:string - listOfUpperOntologyEntities->forEach(e:uml.Class) { - superEntities = superEntities + e.name +"; " - } - verbose(name+": Must derive directly or indirectly from one of the entities of the upper ontology: "+superEntities,true,false) + verbose("*"+name+": Must derive directly or indirectly from one of the entities of the upper ontology\n",true,false) } } } uml.Class::checkIfFinal():boolean { - return (listOfUpperOntologyEntities.get(self.name) != null) + var ontKeys:list = listOfUpperOntology.keys() + ontKeys->forEach(ontName){ + var listOfUpperOntologyEntities:hashtable = listOfUpperOntology.get(ontName) + if(listOfUpperOntologyEntities.get(self.name) != null){ + return true + } + } + return false } uml.Class::getPropertyList():list { @@ -156,49 +185,58 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. verbose('\tAdding property '+att.name+' (type:'+att.type.name+', size:'+att.name.size()+')',false,false) pList.add(att) - if(att.name.size() == 0) verbose(self.name+": Empty "+att.oclGetType()+" name found",true,false) - - if(att.type == null) verbose(self.name+": Property "+att.name+" has UNDEFINED type",true,false) - else if(!att.isDataType()) verbose(self.name+": Property "+att.name+" has UNKNOWN type",true,false) - + if(att.name.size()>0){ + if(att.association == null) { + if(att.type == null) verbose("!"+self.name+": Property "+att.name+" has UNDEFINED type\n",true,false) + else if(!att.isDataType()) verbose("!"+self.name+": Property "+att.name+" has UNKNOWN type\n",true,false) + } + } } if(pList.isEmpty()){ - verbose(self.name + ": NO properties found",true,false) + verbose("!"+self.name + ": NO properties found\n",true,false) } return pList } uml.Package::checkEmpty (someList:list):boolean { - someList->forEach(e:uml.Classifier) { - verbose("INFO: Element name:"+e.name+", element type:"+e.oclGetType(), false, false) - if(e.name.size() == 0) { - var parent:string - if(e.oclGetType().equals('Class')) parent = e.name - else parent = e.owner.name - verbose(parent+": Empty "+e.oclGetType()+" name not allowed",true,false) - return false + var ret:boolean = true + var howmany:integer = 0 + var parent:string + var type:string + + someList->forEach(e) { + var elementProps:hashtable = e.getElementProps() + if(parent == null) parent = elementProps.get('parent') + if(type == null) type = elementProps.get('type') + verbose("INFO: Element name:"+elementProps.get('name')+", element type:"+type+"\n", false, false) + if(elementProps.get('name').size() == 0) { + howmany = howmany + 1 + ret = false } } - return true + + if(howmany > 0) verbose("*"+parent+"Found "+howmany+" unnamed "+type,true,false) + + return ret + } uml.Package::checkUnity (someList:list):boolean { - var toBeChecked:string - var repetitions:integer var repeatedElements:hashtable - var parent:string var res:boolean = true + var parent:string someList->forEach(e) { - var elementProps:hashtable = e.getElementProps() - parent = elementProps.get('parent') - toBeChecked = elementProps.get('name'); - repetitions = repeatedElements.get(elementProps.get('name')+":"+elementProps.get('type')) + var elementProps:hashtable = e.getElementProps() + var repetitions:integer = repeatedElements.get(elementProps.get('name').toLower()+":"+elementProps.get('type')) + if(parent == null) parent = elementProps.get('parent') + if (repetitions == null) repetitions = 1 else repetitions = repetitions + 1 - repeatedElements.put(elementProps.get('name')+":"+elementProps.get('type'), repetitions) + repeatedElements.put(elementProps.get('name').toLower()+":"+elementProps.get('type'), repetitions) + } if(!repeatedElements.isEmpty()) { @@ -211,7 +249,7 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. var eType:string = e.substring(e.lastIndexOf(":")+1, e.size()) if(times >1){ - verbose(parent+"Duplicate entry for "+eType+" "+eName+" ("+times+" duplicates)",true,false) + verbose("*"+parent+"Multiple "+eType+" with same (case-independent) name ("+times+" duplicates of "+eName+")\n",true,false) res = false } } @@ -249,11 +287,14 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. uml.Model::createSuperentitiesList(){ self.packageImport->forEach(p:uml.PackageImport){ p.relatedElement->forEach(m:uml.Model | m.name.startsWith("org.universaal.")){ + var listOfUpperOntologyEntities:hashtable m.ownedMember->forEach(package:uml.Package){ package.ownedMember->forEach(class:uml.Class){ listOfUpperOntologyEntities.put(class.name,class) + datatypeImportMap.put(class.name,m.name) } } + listOfUpperOntology.put(m.name,listOfUpperOntologyEntities) } } } @@ -286,13 +327,12 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. } // Common check for Class and Property - uml.Element::allowedCharlist():boolean{ + uml.Classifier::allowedCharlist():boolean{ var elementProps:hashtable = self.getElementProps() + var what:string = elementProps.get('name') var type:string = elementProps.get('type') var parent:string = elementProps.get('parent') - // no whitespaces - if(what.contains(" ")) verbose(parent+what+": Spaces not allowed in name's "+type,true,false) // no numbers at the beginning if(what.startsWith("0") || @@ -304,7 +344,7 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. what.startsWith("6") || what.startsWith("7") || what.startsWith("8") || - what.startsWith("9")) verbose(parent+what+": First "+type+" character's name cannot be a number",true,false) + what.startsWith("9")) verbose("*"+parent+what+": First "+type+" character's name cannot be a number\n",true,false) // only alphanumeric chars plus the undescore allowed what = what.replace("[A-za-z0-9_ ]","") @@ -313,10 +353,16 @@ texttransformation validateOntologyUml (in uml:"http://www.eclipse.org/uml2/3.0. verbose(message:string, error:boolean, force:boolean) { if(error){ - message = "*** ERROR *** : " + message - errorsList.add(message) + errorsList.add(message) + if(message.startsWith("*")) errors = errors + 1 + else warnings = warnings + 1 } - if(debugEnabled || force) stdout.println(message) + if(debugEnabled || force){ + if(message.endsWith("\n")) + stdout.println(message.substring(0, message.size()-1)) + else + stdout.print(message) + } if(logEnabled) log(message) } -- GitLab