-- @atlcompiler emftvm -- @nsURI UML2=http://www.eclipse.org/uml2/3.0.0/UML -- @nsURI JAVA=http://www.eclipse.org/gmt/modisco/JavaAST -- $Id$ -- Merges back java method bodies into UML2 source model module Java2UML; create OUT : UML2 from IN : UML2, CODE : JAVA; uses "lib::UML2"; uses "lib::Mappings"; uses UML2Copy; -- ====================================================================== -- model-specific helpers begin -- ====================================================================== helper def : language : String = 'language'.value(); helper context UML2!"uml::Classifier" def : isApplet : Boolean = not self.getAppliedStereotype('Applet::Applet').oclIsUndefined(); helper context UML2!"uml::Classifier" def : isSingleton : Boolean = not self.getAppliedStereotype('Singleton::Singleton').oclIsUndefined(); helper context UML2!"uml::Operation" def : isAsynchronous : Boolean = not self.getAppliedStereotype('Async::asynchronous').oclIsUndefined(); helper context UML2!"uml::Classifier" def : typeDeclaration : JAVA!TypeDeclaration = let owner : OclAny = self.refImmediateComposite() in if (owner.oclIsKindOf(UML2!"uml::Classifier")) then owner.typeDeclaration.bodyDeclarations ->select(b|b.oclIsKindOf(JAVA!AbstractTypeDeclaration)) ->any(t|t.name.fullyQualifiedName = self.name) else JAVA!CompilationUnit.allInstances() ->select(c|c.package.name.fullyQualifiedName = self.getNearestPackage().qualifiedName('.')) ->collect(c|c.types)->flatten() ->any(t|t.name.fullyQualifiedName = self.name) endif; helper context UML2!"uml::BehavioralFeature" def : javaMethodDeclaration : JAVA!MethodDeclaration = let t : JAVA!TypeDeclaration = self.namespace.typeDeclaration in t.bodyDeclarations ->select(b|b.oclIsKindOf(JAVA!MethodDeclaration)) ->select(m|m.name.fullyQualifiedName = self.name) ->select(m| if self.getType().oclIsUndefined() then if m.returnType.oclIsUndefined() then true else m.returnType.lexicalForm = 'void' endif else if m.constructor then t.name.lexicalForm = self.getType().name -- constructors already have naming constraints, so this check is not strictly necessary else if m.returnType.oclIsUndefined() then false else if self.getType().oclIsKindOf(UML2!"uml::PrimitiveType") then let implTypeName : String = self.getType().name.implTypeName().replaceAll('::', '.') in m.returnType.lexicalForm = implTypeName or 'java.lang.' + m.returnType.lexicalForm = implTypeName else m.returnType.lexicalForm = self.getType().qualifiedName('.') endif endif endif endif) ->any(m|thisModule.equivalentParameters(self.ownedParameter->reject(p|p.direction = #return), m.parameters)); helper def : equivalentParameters(selfpars : Sequence(UML2!"uml::Parameter"), otherpars : Sequence(JAVA!SingleVariableDeclaration)) : Boolean = if selfpars.isEmpty() or otherpars.isEmpty() then selfpars.isEmpty() and otherpars.isEmpty() else let selfpar : UML2!"uml::Parameter" = selfpars->first() in let otherpar : JAVA!SingleVariableDeclaration = otherpars->first() in if selfpar.oclIsUndefined() then otherpar.oclIsUndefined() else selfpar.equivalentTo(otherpar) and thisModule.equivalentParameters( selfpars->excluding(selfpar), otherpars->excluding(otherpar)) endif endif; helper context UML2!"uml::Parameter" def : equivalentTo(v : JAVA!SingleVariableDeclaration) : Boolean = not v.oclIsUndefined() and if self.type.oclIsUndefined() then v.type.lexicalForm = 'void' else if self.type.oclIsKindOf(UML2!"uml::PrimitiveType") then let implTypeName : String = self.type.name.implTypeName().replaceAll('::', '.') in v.type.lexicalForm = implTypeName or 'java.lang.' + v.type.lexicalForm = implTypeName else v.type.lexicalForm = self.type.qualifiedName('.') endif endif; helper context UML2!"uml::Operation" def : filteredBody() : String = self.appletFilteredBody( self.asyncFilteredBody( let jmd : JAVA!MethodDeclaration = self.javaMethodDeclaration in jmd.body.statements)) ->iterate(e; acc : String = '' | if acc = '' then acc + e.lexicalForm else acc + '\n' + e.lexicalForm endif); helper context UML2!"uml::Operation" def : asyncFilteredBody(statements : Sequence(JAVA!Statement)) : Sequence(JAVA!Statement) = if self.isAsynchronous then statements->first() -- JAVA!ExpressionStatement ("new Thread() {public void run() {...}}.start();") .expression -- JAVA!MethodInvocation ("new Thread() {public void run() {...}}.start()") .expression -- JAVA!ClassInstanceCreation ("new Thread() {public void run() {...}}") .anonymousClassDeclaration -- JAVA!AnonymousClassDeclaration ("{public void run() {...}}") .bodyDeclarations.first() -- JAVA!MethodDeclaration ("public void run() {...}") .body -- JAVA!Block ("{...}") .statements -- Sequence(JAVA!Statement) ("...") else statements endif; helper context UML2!"uml::Operation" def : appletFilteredBody(statements : Sequence(JAVA!Statement)) : Sequence(JAVA!Statement) = if self.isAppletInit then let fStatements : Sequence(JAVA!Statement) = if self.class.isSingleton then statements->excluding(statements->first()) -- JAVA!ExpressionStatement ("instance = this;") else statements endif in if self.class.isJavaAppletApplet.debug(self.class.toString() + '.isJavaAppletApplet') then fStatements->excluding(fStatements->first()) -- JAVA!ExpressionStatement ("setLayout(new java.awt.BorderLayout());") else fStatements endif else statements endif; helper context UML2!"uml::Operation" def : isAppletInit : Boolean = self.name = 'init' and self.class.isApplet; helper context UML2!"uml::Classifier" def : isJavaAppletApplet : Boolean = self.typeDeclaration.superclassType.name.fullyQualifiedName = 'java.applet.Applet'; helper context UML2!"uml::Operation" def : hasJavaBody : Boolean = not self.javaMethodDeclaration.oclIsUndefined() and not self.javaMethodDeclaration.body.oclIsUndefined() and self.javaMethodDeclaration.body.statements->notEmpty(); -- ====================================================================== -- model-specific helpers end -- ====================================================================== -- ====================================================================== -- transformation rules begin -- ====================================================================== rule Class { from s : UML2!"uml::Class" in IN ( s.oclIsTypeOf(UML2!"uml::Class")) using { myOperations : Set(UML2!"uml::Operation") = s.ownedOperation ->select(o|o.method->isEmpty() and o.hasJavaBody); } to t : UML2!"uml::Class" ( __xmiID__ <- s.__xmiID__, name <- s.name, visibility <- s.visibility, isLeaf <- s.isLeaf, isAbstract <- s.isAbstract, isActive <- s.isActive, eAnnotations <- s.eAnnotations, ownedComment <- s.ownedComment, clientDependency <- s.clientDependency, nameExpression <- s.nameExpression, elementImport <- s.elementImport, packageImport <- s.packageImport, ownedRule <- s.ownedRule, templateParameter <- s.templateParameter, templateBinding <- s.templateBinding, ownedTemplateSignature <- s.ownedTemplateSignature, generalization <- s.generalization, powertypeExtent <- s.powertypeExtent, redefinedClassifier <- s.redefinedClassifier, substitution <- s.substitution, representation <- s.representation, collaborationUse <- s.collaborationUse, ownedUseCase <- s.ownedUseCase, useCase <- s.useCase, ownedAttribute <- s.ownedAttribute, ownedConnector <- s.ownedConnector, ownedBehavior <- s.ownedBehavior ->union(myOperations->collect(o| thisModule.resolveTemp(o, 'javaMethod'))), classifierBehavior <- s.classifierBehavior, interfaceRealization <- s.interfaceRealization, ownedTrigger <- s.ownedTrigger, nestedClassifier <- s.nestedClassifier, ownedOperation <- s.ownedOperation, ownedReception <- s.ownedReception) } rule Operation { from s : UML2!"uml::Operation" in IN to t : UML2!"uml::Operation" ( __xmiID__ <- s.__xmiID__, name <- s.name, visibility <- s.visibility, isLeaf <- s.isLeaf, isStatic <- s.isStatic, isAbstract <- s.isAbstract, concurrency <- s.concurrency, isQuery <- s.isQuery, eAnnotations <- s.eAnnotations, ownedComment <- s.ownedComment, clientDependency <- s.clientDependency, nameExpression <- s.nameExpression, elementImport <- s.elementImport, packageImport <- s.packageImport, ownedRule <- s.ownedRule, ownedParameter <- s.ownedParameter, method <- s.method, raisedException <- s.raisedException, ownedParameterSet <- s.ownedParameterSet, templateParameter <- s.templateParameter, templateBinding <- s.templateBinding, ownedTemplateSignature <- s.ownedTemplateSignature, precondition <- s.precondition, postcondition <- s.postcondition, redefinedOperation <- s.redefinedOperation, bodyCondition <- s.bodyCondition) } rule EmptyOperation extends Operation { from s : UML2!"uml::Operation" in IN ( s.method->isEmpty() and s.hasJavaBody) to t : UML2!"uml::Operation" ( name <- s.name.debug('EmptyOperation')), -- Java method body javaMethod : UML2!"uml::OpaqueBehavior" ( specification <- s, name <- s.name + 'Behavior', language <- Sequence{thisModule.language}, body <- Sequence{s.filteredBody()}, ownedParameter <- s.ownedParameter->collect(p|thisModule.CopyParameter(p))) } lazy rule CopyParameter { from s : UML2!"uml::Parameter" to t : UML2!"uml::Parameter" ( name <- s.name, visibility <- s.visibility, isOrdered <- s.isOrdered, isUnique <- s.isUnique, direction <- s.direction, isException <- s.isException, isStream <- s.isStream, effect <- s.effect, clientDependency <- s.clientDependency, type <- s.type) do { t.setLower(s.getLower()); t.setUpper(s.getUpper()); t; } } rule OpaqueBehavior { from s : UML2!"uml::OpaqueBehavior" in IN ( s.oclIsTypeOf(UML2!"uml::OpaqueBehavior")) to t : UML2!"uml::OpaqueBehavior" ( __xmiID__ <- s.__xmiID__, name <- s.name, visibility <- s.visibility, isLeaf <- s.isLeaf, isAbstract <- s.isAbstract, isActive <- s.isActive, isReentrant <- s.isReentrant, body <- s.body, language <- s.language, eAnnotations <- s.eAnnotations, ownedComment <- s.ownedComment, clientDependency <- s.clientDependency, nameExpression <- s.nameExpression, elementImport <- s.elementImport, packageImport <- s.packageImport, ownedRule <- s.ownedRule, templateParameter <- s.templateParameter, templateBinding <- s.templateBinding, ownedTemplateSignature <- s.ownedTemplateSignature, generalization <- s.generalization, powertypeExtent <- s.powertypeExtent, redefinedClassifier <- s.redefinedClassifier, substitution <- s.substitution, representation <- s.representation, collaborationUse <- s.collaborationUse, ownedUseCase <- s.ownedUseCase, useCase <- s.useCase, ownedAttribute <- s.ownedAttribute, ownedConnector <- s.ownedConnector, ownedBehavior <- s.ownedBehavior, classifierBehavior <- s.classifierBehavior, interfaceRealization <- s.interfaceRealization, ownedTrigger <- s.ownedTrigger, nestedClassifier <- s.nestedClassifier, ownedOperation <- s.ownedOperation, ownedReception <- s.ownedReception, redefinedBehavior <- s.redefinedBehavior, ownedParameter <- s.ownedParameter, precondition <- s.precondition, postcondition <- s.postcondition, ownedParameterSet <- s.ownedParameterSet, specification <- s.specification) } rule JavaOpaqueBehavior extends OpaqueBehavior { from s : UML2!"uml::OpaqueBehavior" in IN ( s.language.includes('java') and not s.specification.oclIsUndefined() and not s.specification.javaMethodDeclaration.oclIsUndefined()) using { index : Integer = s.language->indexOf('java'); } to t : UML2!"uml::OpaqueBehavior" ( name <- s.name.debug('JavaOpaqueBehavior'), body <- s.body->excluding(s.body->at(index)) ->insertAt(index, s.specification.filteredBody())) } -- ====================================================================== -- transformation rules end -- ======================================================================