001/* 002 * Copyright c 2018 Rusi Popov, MDA Tools.net All rights reserved. 003 * 004 * This program and the accompanying materials are made available under the terms of the 005 * Eclipse Public License v2.0 which accompanies this distribution, and is available at 006 * http://www.eclipse.org/legal/epl-v20.html 007 */ 008package net.mdatools.modelant.uml13.reverse; 009 010import java.util.ArrayList; 011import java.util.Collection; 012import java.util.Iterator; 013 014import javax.jmi.reflect.RefObject; 015import javax.jmi.reflect.RefPackage; 016 017import org.omg.uml13.foundation.core.AssociationEnd; 018import org.omg.uml13.foundation.core.Attribute; 019import org.omg.uml13.foundation.core.Classifier; 020import org.omg.uml13.foundation.core.DataType; 021import org.omg.uml13.foundation.core.Dependency; 022import org.omg.uml13.foundation.core.Generalization; 023import org.omg.uml13.foundation.core.Interface; 024import org.omg.uml13.foundation.core.ModelElement; 025import org.omg.uml13.foundation.core.Namespace; 026import org.omg.uml13.foundation.core.Operation; 027import org.omg.uml13.foundation.core.Parameter; 028import org.omg.uml13.foundation.core.UmlAssociation; 029import org.omg.uml13.foundation.core.UmlClass; 030import org.omg.uml13.foundation.datatypes.AggregationKindEnum; 031import org.omg.uml13.foundation.datatypes.Expression; 032import org.omg.uml13.foundation.datatypes.Multiplicity; 033import org.omg.uml13.foundation.datatypes.MultiplicityRange; 034import org.omg.uml13.foundation.datatypes.ScopeKindEnum; 035import org.omg.uml13.foundation.datatypes.VisibilityKindEnum; 036import org.omg.uml13.foundation.extensionmechanisms.Stereotype; 037import org.omg.uml13.foundation.extensionmechanisms.TaggedValue; 038import org.omg.uml13.modelmanagement.Model; 039import org.omg.uml13.modelmanagement.ModelClass; 040import org.omg.uml13.modelmanagement.UmlPackage; 041 042import net.mdatools.modelant.core.api.name.ClassName; 043import net.mdatools.modelant.core.api.name.Name; 044import net.mdatools.modelant.core.api.name.PackageName; 045import net.mdatools.modelant.core.name.ClassNameImpl; 046import net.mdatools.modelant.core.name.NameImpl; 047import net.mdatools.modelant.core.name.PackageNameImpl; 048 049public class Uml13ModelFactory { 050 051 /** 052 * The stereotype that indicates the ELEMENT declarations in the XSD 053 */ 054 public static final String STEREOTYPE_ELEMENT = "element"; 055 056 private static final PackageName foundation; 057 private static final PackageName core; 058 private static final PackageName modelManagement; 059 private static final PackageName dataTypes; 060 private static final PackageName extensionMechanisms; 061 private static final PackageName bebehavioralElements; 062 private static final PackageName commonBehavior; 063 private static final ClassName taggedValue; 064 private static final ClassName attribute; 065 private static final ClassName parameter; 066 private static final ClassName className; 067 private static final ClassName interfaceName; 068 private static final ClassName dependencyName; 069 private static final ClassName exceptionName; 070 private static final ClassName expression; 071 private static final ClassName umlPackage; 072 private static final ClassName stereotype; 073 private static final ClassName modelName; 074 private static final ClassName generalization; 075 private static final ClassName operationName; 076 private static final ClassName association; 077 private static final ClassName associationEnd; 078 private static final ClassName multiplicity; 079 private static final ClassName multiplicityRange; 080 private static final ClassName dataType; 081 082 static { 083 foundation = new PackageNameImpl("Foundation"); 084 core = new PackageNameImpl(foundation, "Core"); 085 dataTypes = new PackageNameImpl(foundation, "Data_Types"); 086 extensionMechanisms = new PackageNameImpl(foundation, "Extension_Mechanisms"); 087 088 modelManagement = new PackageNameImpl("Model_Management"); 089 090 bebehavioralElements = new PackageNameImpl("Behavioral_Elements"); 091 commonBehavior = new PackageNameImpl(bebehavioralElements,"Common_Behavior"); 092 093 taggedValue = new ClassNameImpl(extensionMechanisms, "TaggedValue"); 094 attribute = new ClassNameImpl(core, "Attribute"); 095 parameter = new ClassNameImpl(core, "Parameter"); 096 097 className = new ClassNameImpl(core, "Class"); 098 interfaceName = new ClassNameImpl(core, "Interface"); 099 exceptionName = new ClassNameImpl(commonBehavior, "Exception"); 100 operationName = new ClassNameImpl(core, "Operation"); 101 dependencyName= new ClassNameImpl(core, "Dependency"); 102 103 association = new ClassNameImpl(core, "Association"); 104 associationEnd = new ClassNameImpl(core, "AssociationEnd"); 105 dataType = new ClassNameImpl(core, "DataType"); 106 expression = new ClassNameImpl(dataTypes, "Expression"); 107 umlPackage = new ClassNameImpl(modelManagement, "Package"); 108 modelName = new ClassNameImpl(modelManagement, "Model"); 109 stereotype = new ClassNameImpl(extensionMechanisms, "Stereotype"); 110 generalization = new ClassNameImpl(core, "Generalization"); 111 112 multiplicity = new ClassNameImpl(dataTypes, "Multiplicity"); 113 multiplicityRange = new ClassNameImpl(dataTypes, "MultiplicityRange"); 114 } 115 116 private final RefPackage extent; 117 private final Model model; 118 119 public Uml13ModelFactory(RefPackage extent) { 120 this.extent = extent; 121 this.model = constructModel(extent); 122 } 123 124 private Model constructModel(RefPackage extent) { 125 Model result; 126 ModelClass metaClass; 127 Collection<Model> allModels; 128 129 metaClass = (ModelClass) modelName.getMetaClass( extent ); 130 allModels = metaClass.refAllOfClass(); 131 if ( allModels.isEmpty() ) { 132 result = (Model) metaClass.refCreateInstance( null ); 133 } else { 134 result = allModels.iterator().next(); 135 } 136 return result; 137 } 138 139 public void setModelName(String modelName) { 140 model.setName( modelName ); 141 } 142 143 public UmlAssociation constructAssociation(Classifier thisClass, 144 String thisRole, 145 int thisEndUpper, 146 boolean isComposition, 147 boolean isThisNavigable, 148 Classifier otherClass, 149 String otherRole, 150 int otherEndUpper, 151 Namespace namespace, 152 String documentation) { 153 UmlAssociation result; 154 AssociationEnd thisEnd; 155 156 result = (UmlAssociation) association.getMetaClass( extent ).refCreateInstance( null ); 157 result.setNamespace( namespace ); 158 result.setName( "" ); 159 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 160 161 // this end (the class with the associative attribute) 162 thisEnd = constructAssociationEnd( thisClass, thisRole, thisEndUpper, result ); 163 164 if ( isComposition ) { 165 thisEnd.setAggregation( AggregationKindEnum.AK_COMPOSITE ); 166 } 167 168 constructAssociationEnd( otherClass, otherRole, otherEndUpper, result ); 169 170 return result; 171 } 172 173 private AssociationEnd constructAssociationEnd(Classifier thisClass, 174 String thisRole, 175 int thisEndUpper, 176 UmlAssociation result) { 177 AssociationEnd thisEnd; 178 179 thisEnd = (AssociationEnd) associationEnd.getMetaClass( extent ).refCreateInstance( null ); 180 thisEnd.setName( thisRole ); 181 thisEnd.setType( thisClass ); 182 thisEnd.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 183 thisEnd.setAssociation( result ); 184 thisEnd.setMultiplicity( constructMultiplicity( thisEndUpper ) ); 185 186 return thisEnd; 187 } 188 189 public Multiplicity constructMultiplicity(int otherEndUpper) { 190 Multiplicity result; 191 MultiplicityRange range; 192 193 result = (Multiplicity) multiplicity.getMetaClass( extent ).refCreateInstance( null ); 194 195 range = (MultiplicityRange) multiplicityRange.getMetaClass( extent ).refCreateInstance( null ); 196 range.setUpper( otherEndUpper ); 197 result.getRange().add(range); 198 199 return result; 200 } 201 202 public UmlClass constructClass(String simpleTypeName) { 203 return constructClass( model, simpleTypeName ); 204 } 205 206 public UmlClass constructClass(Namespace namespace, String simpleTypeName) { 207 UmlClass result; 208 Object lookedUp; 209 210 lookedUp = locateLocalModelElement( namespace, simpleTypeName ); 211 if ( lookedUp == null ) { // none found - build it 212 result = (UmlClass) className.getMetaClass( extent ).refCreateInstance( null ); 213 214 result.setName( simpleTypeName ); 215 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 216 result.setNamespace( namespace ); 217 218 } else if ( lookedUp instanceof UmlClass ) { 219 result = (UmlClass) lookedUp; 220 221 } else { 222 throw new IllegalArgumentException("Expected to lookup a UmlClass instance for the name: "+namespace.getName()+"."+simpleTypeName+" isntead of "+lookedUp); 223 } 224 return result; 225 } 226 227 /** 228 * Construct the data type with the name 229 * @param dataTypeName is the non-null type name 230 * @return the data type identified or class identified 231 */ 232 public DataType constructDataType(String dataTypeName) { 233 DataType result; 234 235 try { 236 result = (DataType) locateModelElement(dataTypeName); 237 238 } catch (IllegalArgumentException ex) { // data type not found 239 result = (DataType) dataType.getMetaClass( extent ).refCreateInstance( null ); 240 result.setName( dataTypeName ); 241 result.setNamespace( model ); 242 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 243 244 } 245 return result; 246 } 247 248 public Attribute constructAttribute(String name) { 249 Attribute result; 250 251 result = (Attribute) attribute.getMetaClass( extent ).refCreateInstance( null ); 252 253 result.setName( name ); 254 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 255 result.setOwnerScope( ScopeKindEnum.SK_INSTANCE ); 256 257 return result; 258 } 259 260 public Parameter constructParameter(String name) { 261 Parameter result; 262 263 result = (Parameter) parameter.getMetaClass( extent ).refCreateInstance( null ); 264 265 result.setName( name ); 266 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 267 268 return result; 269 } 270 271 public Expression constructExpression(String body) { 272 Expression result; 273 274 result = (Expression) expression.getMetaClass( extent ).refCreateInstance( null ); 275 result.setBody( body ); 276 277 return result; 278 } 279 280 /** 281 * This method creates the public interface in the package provided 282 * 283 * @param umlPackage the containing package 284 * @param name is the name of the interface to create 285 * @return the interface built 286 */ 287 public Interface constructInterface(Namespace umlPackage, String name) { 288 Interface result = (Interface) locateLocalModelElement( umlPackage, name ); 289 290 if ( result == null ) { // none found - build it 291 result = (Interface) interfaceName.getMetaClass( extent ).refCreateInstance(null); 292 result.setName( name ); 293 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 294 result.setNamespace( umlPackage ); 295 } 296 return result; 297 } 298 299 /** 300 * Instantiate a public exception with the qualified name provided, but the Exceptions might be messed with the regular classes so they 301 * are registered as DataTypes at the model level instead of UnlExceprion-s when they are also 302 * reverse engineered. 303 * @param qualifiedName of the exception to be created 304 * @return the newly created public exception 305 */ 306 public Classifier constructException(String qualifiedName) { 307 Classifier result = (Classifier) locateLocalModelElement( model, qualifiedName ); 308 309 if ( result == null ) { // still not created, thus it is not included 310 result = (Classifier) exceptionName.getMetaClass( extent ).refCreateInstance( null ); 311 result.setName( qualifiedName ); 312 result.setNamespace( model ); 313 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 314 } 315 return result; 316 } 317 318 public Operation constructOperation(String name) { 319 Operation result; 320 321 result = (Operation) operationName.getMetaClass( extent ).refCreateInstance( null ); 322 result.setName( name ); 323 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 324 result.setOwnerScope( ScopeKindEnum.SK_INSTANCE ); 325 326 return result; 327 } 328 329 public void constructGeneralization(Classifier subClass, Classifier superClass) { 330 Generalization result; 331 332 result = (Generalization) generalization.getMetaClass( extent ).refCreateInstance( null ); 333 334 result.setNamespace( superClass.getNamespace() ); 335 result.setParent( superClass ); 336 result.setChild( subClass ); 337 338 } 339 340 public Dependency constructDependency(ModelElement client, ModelElement supplier, String name) { 341 Dependency result; 342 343 result = (Dependency) dependencyName.getMetaClass( extent ).refCreateInstance( null ); 344 result.getSupplier().add( supplier ); 345 result.getClient().add( client ); 346 result.setNamespace( model ); 347 result.setSpecification( false ); 348 result.setName( name ); 349 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 350 351 return result; 352 } 353 354 public UmlPackage constructPackage(String name) { 355 return constructPackage( NameImpl.parseQualifiedName(name) ); 356 } 357 358 /** 359 * @param name not null name of the UML package to lookup/construct 360 * @return not null UML package with the name provided from the current model 361 */ 362 public UmlPackage constructPackage(Name name) { 363 UmlPackage result; 364 UmlPackage namespace; 365 366 if ( name.getOwner() == null ) { 367 namespace = model; 368 } else { 369 namespace = constructPackage( name.getOwner() ); 370 } 371 372 result = (UmlPackage) locateLocalModelElement( namespace, name.getName() ); 373 if ( result == null ) { // still not created, thus it is not included 374 result = (UmlPackage) umlPackage.getMetaClass( extent ).refCreateInstance( null ); 375 result.setName( name.getName() ); 376 result.setNamespace( namespace ); 377 } 378 return result; 379 } 380 381 public void constructStereotypeElement(ModelElement extendedElement) { 382 constructStereotype( extendedElement, STEREOTYPE_ELEMENT ); 383 } 384 385 public void constructStereotype(ModelElement extendedElement, String name) { 386 Stereotype result; 387 388 result = (Stereotype) locateLocalModelElement( model, name ); 389 if ( result == null ) { // still not created, thus it is not included 390 result = (Stereotype) stereotype.getMetaClass( extent ).refCreateInstance( null ); 391 392 result.setName( name ); 393 result.setNamespace( model ); 394 result.setVisibility( VisibilityKindEnum.VK_PUBLIC ); 395 } 396 result.getExtendedElement().add( extendedElement ); 397 } 398 399 /** 400 * @param tagName a non-null tag name 401 * @return the tag with the name bound to this model element 402 */ 403 public TaggedValue getTaggedValue(ModelElement modelElement, String tagName) { 404 TaggedValue result = null; 405 TaggedValue tag; 406 Iterator<TaggedValue> sourceIterator; 407 408 sourceIterator = allTaggedValues(modelElement).iterator(); 409 while ( result == null && sourceIterator.hasNext() ) { 410 tag = sourceIterator.next(); 411 412 if ( tagName.equals( tag.getTag() ) ) { 413 result = tag; 414 } 415 } 416 return result; 417 } 418 419 public void constructTagDocumentation(ModelElement otherClass, String contents) { 420 TaggedValue documentation; 421 422 documentation = getTaggedValue( otherClass, net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_DOCUMENTATION); 423 if ( documentation == null ) { 424 constructTag( otherClass, net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_DOCUMENTATION, contents ); 425 426 } else if ( documentation.getValue() == null ) { 427 documentation.setValue(contents); 428 429 } else if ( documentation.getValue().indexOf( contents ) < 0 ) { 430 documentation.setValue(documentation.getValue()+"\n\r"+contents); 431 } 432 } 433 434 /** 435 * @param modelElement is a non-null model element. 436 * @return a non-null collection of tagged values bound to that model element 437 */ 438 private Collection<TaggedValue> allTaggedValues(ModelElement modelElement) { 439 Collection<TaggedValue> result; 440 TaggedValue tag; 441 Iterator sourceIterator; 442 443 result = new ArrayList<TaggedValue>(); 444 445 sourceIterator = taggedValue.getMetaClass( extent ).refAllOfClass().iterator(); 446 while ( sourceIterator.hasNext() ) { 447 tag = (TaggedValue) sourceIterator.next(); 448 449 if ( tag.getModelElement() == modelElement ) { 450 result.add( tag ); 451 } 452 } 453 return result; 454 } 455 456 public void constructTag(ModelElement modelElement, String name, String value) { 457 TaggedValue result; 458 459 result = (TaggedValue) taggedValue.getMetaClass( extent ).refCreateInstance( null ); 460 461 result.setTag( name ); 462 result.setValue( value ); 463 result.setModelElement( modelElement ); 464 } 465 466 public void constructTagFieldPrecision(ModelElement intoClass, int precision) { 467 constructTag(intoClass, 468 net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_DATA_TYPE_PRECISION, 469 "" + precision ); 470 } 471 472 public void constructTagSize(ModelElement intoClass, int parseInt) { 473 constructTag(intoClass, 474 net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_DATA_LENGTH, 475 "" + parseInt ); 476 } 477 478 public void constructTagPersistent(UmlClass intoClass) { 479 constructTag(intoClass, 480 net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_PERSISTENCE, 481 net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_PERSISTENCE_VALUE ); 482 } 483 484 public void constructTagPrimaryKey(Attribute attribute, int order) { 485 constructTag(attribute, 486 net.mdatools.modelant.uml13.metamodel.Convention.TAG_VALUE_PRIMARY_KEY, 487 Integer.toString( order )); 488 } 489 490 /** 491 * Locate the model element using its qualified name in this model object. The empty 492 * (string) name is recognized as the name of the default package - the model itself. 493 * 494 * @param qualifiedName is a non-empty string with the qualified name of a model element 495 * @return the non-null model element with the name specified. 496 */ 497 public RefObject locateModelElement(String qualifiedName) throws IllegalArgumentException { 498 return locateModelElement( model, NameImpl.parseQualifiedName(qualifiedName)); 499 } 500 501 /** 502 * Locate the model element using its qualified Name in this model object. 503 * @param name is a non-empty qualified name of a model element 504 * 505 * @return the model element with the name specified. 506 */ 507 public RefObject locateModelElement(Name<?> name) throws IllegalArgumentException { 508 return locateModelElement(model, name); 509 } 510 511 512 /** 513 * Locate the model element using its Name in this model object. 514 * @param namespace not null namespace to look for the name 515 * @param name not null element name 516 * @return the non-null model element with the name specified. 517 * @throws IllegalArgumentException when not found 518 */ 519 public RefObject locateModelElement(Namespace namespace, Name<?> name) throws IllegalArgumentException { 520 RefObject result; 521 RefObject resultNamespace; 522 523 if ( name.getOwner() != null ) { 524 resultNamespace = locateModelElement(namespace, name.getOwner()); 525 } else { 526 resultNamespace = namespace; 527 } 528 529 // TODO: Reconsider the locateRelativeModelElement to throw exception when not applicable or found nothing (N/A again) 530 531 if ( !(resultNamespace instanceof Namespace) ) { 532 throw new IllegalArgumentException("Looking up "+name.getOwner()+" reached a non-namespace element to lookup "+name.getName()); 533 } 534 result = locateLocalModelElement((Namespace) resultNamespace, name.getName()); 535 536 if (result == null ) { 537 throw new IllegalArgumentException("Not found "+name+" in "+name.getOwner()+" namespace"); 538 } 539 540 return result; 541 } 542 543 /** 544 * This method locates the model element with name provided in <b>elementName </b> within the UML 545 * namespace <b>outerPackage </b>. 546 * 547 * @param elementName is a non-null name 548 * @return null if no package found, otherwise the package with the name specified 549 */ 550 public ModelElement locateLocalModelElement(Namespace namespace, String elementName) { 551 ModelElement result = null; 552 ModelElement ownedElement; 553 Iterator ownedElementsIterator; 554 555 ownedElementsIterator = namespace.getOwnedElement().iterator(); 556 while ( result == null && ownedElementsIterator.hasNext() ) { 557 ownedElement = (ModelElement) ownedElementsIterator.next(); 558 559 if ( elementName.equals( ownedElement.getName() ) ) { 560 result = ownedElement; 561 } 562 } 563 return result; 564 } 565}