Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'proprietary/bundles/org.eclipse.upr.platform.java.cm2up/src/org/eclipse/upr/platform/java/cm2up/CodeModel2UMLProfile.atl')
-rw-r--r--proprietary/bundles/org.eclipse.upr.platform.java.cm2up/src/org/eclipse/upr/platform/java/cm2up/CodeModel2UMLProfile.atl1205
1 files changed, 1205 insertions, 0 deletions
diff --git a/proprietary/bundles/org.eclipse.upr.platform.java.cm2up/src/org/eclipse/upr/platform/java/cm2up/CodeModel2UMLProfile.atl b/proprietary/bundles/org.eclipse.upr.platform.java.cm2up/src/org/eclipse/upr/platform/java/cm2up/CodeModel2UMLProfile.atl
new file mode 100644
index 0000000..eacc8c7
--- /dev/null
+++ b/proprietary/bundles/org.eclipse.upr.platform.java.cm2up/src/org/eclipse/upr/platform/java/cm2up/CodeModel2UMLProfile.atl
@@ -0,0 +1,1205 @@
+--/*******************************************************************************
+-- * Copyright (c) 2015 Vienna University of Technology.
+-- * All rights reserved. This program and the accompanying materials
+-- * are made available under the terms of the Eclipse Public License v1.0
+-- * which accompanies this distribution, and is available at
+-- * http://www.eclipse.org/legal/epl-v10.html
+-- *
+-- * Contributors:
+-- * Alexander Bergmayr (TU Wien) - initial API and implementation
+-- * Manuel Wimmer (TU Wien) - initial API and implementation
+-- *
+-- * Initially developed in the context of ARTIST EU project www.artist-project.eu
+-- *******************************************************************************/
+
+-- @nsURI UMLMM=http://www.eclipse.org/uml2/4.0.0/UML
+-- @path JMM=http://www.eclipse.org/MoDisco/Java/0.2.incubation/java
+-- @path TMM=pathmap://METAMODEL/Trace.ecore
+-- @path CFGMM=/eu.artist.migration.mdt.jump.cm2up/metamodel/jump-configuration.ecore
+
+-- Discovers UML Profiles from Java application code, frameworks and libraries.
+
+module CodeModel2UMLProfile;-- creates UP the UML Profile and TM the Trace Model
+-- from CM the Code Model discovered from a Java application / library
+-- JP a Java-based UML Profile that provides Stereotypes for the parameterized types
+ -- and proxies
+-- JPT the Java Primitive Types library provided by the UML implementation
+-- MC the UML meta-classes in terms of a UML model
+-- UPT the UML Primitive Types library provided by the UML implementation
+create UP: UMLMM, TM: TMM from CM: JMM, JP: UMLMM, JPT: UMLMM, MC: UMLMM, UPT: UMLMM,
+ EPT: UMLMM, CFG : CFGMM;
+
+-- TODO: default value of Strings - default values need to be generally revised
+-- TODO: Code-generator: ID annotation nachziehen!
+
+
+-- helpers for Java-based processing
+uses javaLibrary;
+-- helpers for Stereotype application
+uses profileLibrary;
+
+helper def: getAnnotationTypeMemberDeclarations:
+ Sequence(JMM!AnnotationTypeMemberDeclaration) =
+ JMM!AnnotationTypeMemberDeclaration.allInstancesFrom('CM');
+
+helper def: repeatingStereotypesCfg:
+ OclAny =
+ CFGMM!ProfileConfigurationParameter.allInstancesFrom('CFG') -> first().repeatingStereotypes;
+
+helper def: getRepeatableAnnotations:
+ Sequence(JMM!Annotation) =
+ JMM!Annotation.allInstancesFrom('CM') -> select(e | e.type.type.name = 'Repeatable');
+
+-- check if the annotation type is repeatable
+helper context JMM!AnnotationTypeDeclaration def : isRepeatable : Boolean =
+ self.annotations -> exists(e | e.type.type.name = 'Repeatable');
+
+-- check if the annotation type is a container annotation
+helper context JMM!AnnotationTypeDeclaration def : isContainerAnnotation : Boolean =
+ thisModule.getRepeatableAnnotations -> collect(e | e.values) -> flatten() -> exists(e | e.value.type.type = self);
+
+helper context JMM!AnnotationTypeDeclaration def : requiresContainerAnnotation : Boolean =
+ -- thisModule.repeatingStereotypesCfg = 'native' -> we don't need a container stereotype
+ thisModule.repeatingStereotypesCfg = #composition or thisModule.repeatingStereotypesCfg = #emulation;
+
+helper def: getStereotypes: Sequence(UMLMM!Stereotype) =
+ UMLMM!Stereotype.allInstancesFrom('JP');
+
+helper def: profile: UMLMM!Profile =
+ OclUndefined;
+
+helper def: stereotype: UMLMM!Stereotype =
+ OclUndefined;
+
+helper def: proxyPackage: UMLMM!Package =
+ OclUndefined;
+
+helper def: trace: TMM!Trace =
+ OclUndefined;
+
+-- ensure that the trace model is generated
+entrypoint rule createTrace() {
+ to
+ tr: TMM!Trace (
+ )
+ do {
+ thisModule.trace <- tr;
+ }
+}
+
+-- init package for proxy elements
+lazy rule initProxyPackage {
+ from
+ s1: JMM!Type
+ to
+ t1: UMLMM!Package (
+ name <- 'proxy'
+ )
+ do {
+ thisModule.profile.packagedElement <- t1;
+ thisModule.proxyPackage <- t1;
+
+ t1.applyProfile(UMLMM!Profile.allInstancesFrom('JP').first());
+ }
+}
+
+-- create the profile
+rule Model2Profile {
+ from
+ s1: JMM!Model
+ to
+ t1: UMLMM!Profile (
+ -- packageImport <- Sequence{jpt, mc, upt},
+ packageImport <- Sequence{mc,
+ upt},
+ metamodelReference <- mc,
+ name <- s1.name,
+ packagedElement <- s1.ownedElements -> select(e | not e.proxy and e.
+ isAnnotationTypeContainer)
+ ),
+ -- java primitive types
+-- jpt : UMLMM!PackageImport(
+-- importedPackage <- UMLMM!Model.allInstancesFrom('JPT').first()
+-- ),
+ -- uml meta-classes
+ mc: UMLMM!PackageImport (
+ importedPackage <- UMLMM!Model.allInstancesFrom('MC').first()
+ ),
+ -- uml primitive types
+ upt: UMLMM!PackageImport (
+ importedPackage <- UMLMM!Model.allInstancesFrom('UPT').first()
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'Model2Profile',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- global access to the profile
+ thisModule.profile <- t1;
+ -- apply the profile for java generics / proxies
+ t1.applyProfile(UMLMM!Profile.allInstancesFrom('JP').first());
+ thisModule.stereotype <- UMLMM!Stereotype.allInstancesFrom('JP') -> any(e | e.name = 'JProfile');
+ t1.applyStereotype(thisModule.stereotype);
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule Package2Package {
+ from
+ s1: JMM!Package (
+ not s1.proxy and s1.isAnnotationTypeContainer
+ )
+ to
+ t1: UMLMM!Package (
+ name <- s1.name,
+ packagedElement <- s1.ownedPackages -> select(e | not e.proxy and
+ e.isAnnotationTypeContainer) --,
+ -- instead of selecting all required elements here let's do it in the
+ -- corresponding rules
+ -- of ClassDeclaration, EnumDeclaration, InterfaceDeclaration,
+ -- AnnotationTypeDeclaration
+-- packagedElement <- s1.ownedElements
+
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'Package2Package',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+-- but only enumerations that are required for the profile
+rule EnumDeclaration2Enumeration {
+ from
+ s1: JMM!EnumDeclaration (
+ s1.isEnumerationRelevant
+ )
+ to
+ t1: UMLMM!Enumeration (
+ name <- if (s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) then
+ s1.name
+ else
+ s1.name.concat('From').concat(s1.refImmediateComposite().name)
+ endif,
+ ownedLiteral <- s1.enumConstants -> select(e | not e.proxy or e.
+ refImmediateComposite().isEnumerationRelevant),
+ -- TODO: new CHECK !!
+ ownedAttribute <- s1.bodyDeclarations -> select(e | e.
+ oclIsTypeOf(JMM!FieldDeclaration)),
+ -- with 'not e.proxy' we exclude the 'valueOf' method generated by the java
+ -- compiler
+ ownedOperation <- s1.bodyDeclarations -> select(e | e.
+ oclIsTypeOf(JMM!MethodDeclaration) and not e.proxy)
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'EnumDeclaration2Enumeration',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- if the required class declaration is a proxy then the proxy stereotype is
+ -- applied
+ if(s1.proxy = true) {
+ if(thisModule.proxyPackage.oclIsUndefined()) {
+ thisModule -> initProxyPackage(s1);
+ }
+ thisModule.proxyPackage.packagedElement <- t1;
+
+ -- apply the proxy stereotype
+ thisModule.stereotype <- thisModule.getStereotypes -> select(e | e.name =
+ 'JProxyType').first();
+ t1.applyStereotype(thisModule.stereotype);
+
+ -- set the namepace of the proxy element if available
+ if(s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) {
+ t1.setValue(thisModule.stereotype, 'namespace', s1.
+ refImmediateComposite().getFullyQualifiedPackageName);
+ }
+ else {
+ t1.setValue(thisModule.stereotype, 'namespace', 'NOT_AVAILABLE');
+ }
+ }
+
+ -- elements are contained either by packages or classifiers (nested elements)
+ else {
+ if(not s1.package.oclIsUndefined()) {
+ thisModule.resolveTemp(s1.refImmediateComposite(), 't1').packagedElement
+ <- t1;
+ }
+ else {
+ -- so let's get the package of the owner and put the stereotype there
+ -- ... however
+ -- there is a problem when we generate code !!!!
+ thisModule.resolveTemp(s1.refImmediateComposite().getJavaPackage(), 't1').
+ packagedElement <- t1;
+ }
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule FieldDeclaration2Property {
+ from
+ s1: JMM!FieldDeclaration (
+ not s1.proxy and s1.refImmediateComposite().oclIsTypeOf(JMM!EnumDeclaration)
+ and s1.refImmediateComposite().isEnumerationRelevant
+ )
+ to
+ t1: UMLMM!Property (
+ -- TODO: fragments is 0..* - check the exact behaviour!
+ name <- s1.fragments.first().name,
+ type <- s1.type.getType(),
+ isStatic <- s1.modifier.static
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'FieldDeclaration2Property',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule MethodDeclaration2Operation {
+ from
+ s1: JMM!MethodDeclaration (
+ not s1.proxy and s1.refImmediateComposite().oclIsTypeOf(JMM!EnumDeclaration)
+ and s1.refImmediateComposite().isEnumerationRelevant
+ )
+ to
+ t1: UMLMM!Operation (
+ name <- s1.name,
+ ownedParameter <- s1.parameters -> collect(e | thisModule.createParameter(e))
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'MethodDeclaration2Operation',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- thisModule.applyStereotypes(s1, t1);
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+lazy rule createParameter {
+ from
+ s1: JMM!SingleVariableDeclaration
+ to
+ t1: UMLMM!Parameter (
+ name <- s1.name,
+ type <- s1.type.getType(),
+ direction <- #"in"
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'SingleVariableDeclaration2Paramter',
+ targetElements <- Sequence{t1}
+ )
+ do {
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule EnumConstantDeclaration2EnumerationLiteral {
+ from
+ s1: JMM!EnumConstantDeclaration (
+ s1.refImmediateComposite().isEnumerationRelevant
+ )
+ to
+ t1: UMLMM!EnumerationLiteral (
+ name <- s1.name
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'EnumConstantDeclaration2EnumerationLiteral',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+-- but only classes that are required for the profile. Such classes can only be
+-- bounded type parameters of java.lang.class
+rule ClassDeclaration2Class {
+ from
+ -- since java.lang.Class is mapped to UML class, we need to exclude it here as
+ -- well
+ s1: JMM!ClassDeclaration (
+ (s1.refImmediateComposite().getFullyQualifiedPackageName.concat('.').
+ concat(s1.name) <> 'java.lang.Class') and (thisModule.
+ getAnnotationTypeMemberDeclarations -> select(e | not e.type.
+ oclIsUndefined()) -> select(e | e.type.type.
+ oclIsTypeOf(JMM!ParameterizedType)) -> exists(f | f.type.type.
+ typeArguments -> exists(g | g.type = s1)))
+ )
+ to
+ t1: UMLMM!Class (
+ name <- if (s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) then
+ s1.name
+ else
+ s1.name.concat('From').concat(s1.refImmediateComposite().name)
+ endif
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'ClassDeclaration2Class',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- if the required class declaration is a proxy then the proxy stereotype is
+ -- applied
+ if(s1.proxy = true) {
+ if(thisModule.proxyPackage.oclIsUndefined()) {
+ thisModule -> initProxyPackage(s1);
+ }
+ thisModule.proxyPackage.packagedElement <- t1;
+
+ -- apply the proxy stereotype
+ thisModule.stereotype <- UMLMM!Stereotype.allInstancesFrom('JP') ->
+ select(e | e.name = 'JProxyType').first();
+ t1.applyStereotype(thisModule.stereotype);
+
+ -- set the namepace of the proxy element if available
+ if(s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) {
+ t1.setValue(thisModule.stereotype, 'namespace', s1.
+ refImmediateComposite().getFullyQualifiedPackageName);
+ }
+ else {
+ t1.setValue(thisModule.stereotype, 'namespace', 'NOT_AVAILABLE');
+ }
+ }
+
+ -- nested classifiers are contained by classifiers rather than packages ;)
+ else {
+ if(thisModule.resolveTemp(s1.refImmediateComposite(), 't1').
+ oclIsTypeOf(UMLMM!Package)) {
+ thisModule.resolveTemp(s1.refImmediateComposite(), 't1').packagedElement
+ <- t1;
+ }
+ else {
+ -- so let's get the package of the owner and put the stereotype there
+ -- ... however
+ -- there is a problem when we generate code !!!!
+ thisModule.resolveTemp(s1.refImmediateComposite().getJavaPackage(), 't1').
+ packagedElement <- t1;
+ }
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+-- but only interfaces that are required for the profile. Such classes can only be
+-- bounded type parameters of java.lang.class
+rule InterfaceDeclaration2Interface {
+ from
+ s1: JMM!InterfaceDeclaration (
+ thisModule.getAnnotationTypeMemberDeclarations -> select(e | not e.type.
+ oclIsUndefined()) -> select(e | e.type.type.
+ oclIsTypeOf(JMM!ParameterizedType)) -> exists(f | f.type.type.
+ typeArguments -> exists(g | g.type = s1))
+ )
+ to
+ t1: UMLMM!Interface (
+ name <- if (s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) then
+ s1.name
+ else
+ s1.name.concat('From').concat(s1.refImmediateComposite().name)
+ endif
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'InterfaceDeclaration2Interface',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- if the required class declaration is a proxy then the proxy stereotype is
+ -- applied
+ if(s1.proxy = true) {
+ if(thisModule.proxyPackage.oclIsUndefined()) {
+ thisModule.initProxyPackage(s1);
+ }
+ thisModule.proxyPackage.packagedElement <- t1;
+
+ -- apply the proxy stereotype
+ thisModule.stereotype <- UMLMM!Stereotype.allInstancesFrom('JP') -> select(e
+ | e.name = 'JProxyType').first();
+ t1.applyStereotype(thisModule.stereotype);
+
+ -- set the namepace of the proxy element if available
+ if(s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) {
+ t1.setValue(thisModule.stereotype, 'namespace', s1.
+ refImmediateComposite().getFullyQualifiedPackageName);
+ }
+ else {
+ t1.setValue(thisModule.stereotype, 'namespace', 'NOT_AVAILABLE');
+ }
+ }
+
+ -- nested classifiers are contained by classifiers rather than packages ;)
+ else {
+ if(thisModule.resolveTemp(s1.refImmediateComposite(), 't1').
+ oclIsTypeOf(UMLMM!Package)) {
+ thisModule.resolveTemp(s1.refImmediateComposite(), 't1').packagedElement
+ <- t1;
+ }
+ else {
+ -- so let's get the package of the owner and put the stereotype there
+ -- ... however
+ -- there is a problem when we generate code !!!!
+ thisModule.resolveTemp(s1.refImmediateComposite().getJavaPackage(), 't1').
+ packagedElement <- t1;
+ }
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule AnnotationTypeDeclaration2Stereotype {
+ from
+ -- only those AnnotationTypeDeclarations that are not proxies or return value of
+ -- a AnnotationTypeMemberDeclaration
+ s1: JMM!AnnotationTypeDeclaration (
+ -- isn't a proxy
+ not s1.proxy
+
+ -- is a container stereotype required
+ and ((s1.isContainerAnnotation and s1.requiresContainerAnnotation) or not s1.isContainerAnnotation)
+
+ -- TODO: document this case
+ or thisModule.getAnnotationTypeMemberDeclarations -> select(e | not e.type.oclIsUndefined()) ->
+ select(e | e.type.type.oclIsTypeOf(JMM!ParameterizedType)) -> exists(f | f.type.type.typeArguments ->
+ exists(g | g.type = s1))
+
+ -- we do have a proxy element that has been resolved. This happens if a
+ -- missing library has been added to the build path. If this
+ -- library is not added then an UnresolvedTypeDeclaration
+ -- is discovered by MoDisco.
+ or (s1.proxy and s1.isRelevantForAnnotationTypes)
+ )
+ to
+ t1: UMLMM!Stereotype (
+ name <- if (s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) then
+ s1.name
+ else
+ s1.name.concat('From').concat(s1.refImmediateComposite().name)
+ endif,
+ -- can be set to public as no other visibility modifier is allowed for
+ -- annotation types
+ visibility <- #public,
+ -- should not be done since then the stereotype cannot be instantiated (Java
+ -- Feature or Bug ;) )
+ -- isAbstract <- if s1.modifier.inheritance.toString() = 'abstract' then true
+ -- else false endif,
+
+ -- TODO : According to JLS, an annotation type declaration can also contain
+ -- constant declarations
+ -- class declarations etc. ... even annotation type declarations -> inner
+ -- annotations
+ -- this means bodyDeclarations may also be of type JMM!FieldDeclaration
+
+ -- in findbugs haben wir den Fall einer ClassDeclaration innerhabl eienr
+ -- AnnotationTypeDeclaration,
+ -- see: edu.umd.cs.findbugs.internalAnnotations.SlashedClassName
+ ownedAttribute <- s1.bodyDeclarations -> select(e | e.
+ oclIsTypeOf(JMM!AnnotationTypeMemberDeclaration))
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'AnnotationTypeDeclaration2Stereotype',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ -- if the required class declaration is a proxy then the proxy stereotype is
+ -- applied
+ -- and the stereotype is added to a dedicated proxy package
+ if(s1.proxy) {
+ if(thisModule.proxyPackage.oclIsUndefined()) {
+ thisModule.initProxyPackage(s1);
+ }
+ thisModule.proxyPackage.packagedElement <- t1;
+
+ -- apply the proxy stereotype
+ thisModule.stereotype <- UMLMM!Stereotype.allInstancesFrom('JP') -> select(e
+ | e.name = 'JProxyType').first();
+ t1.applyStereotype(thisModule.stereotype);
+
+ -- set the namepace of the proxy element if available
+ if(s1.refImmediateComposite().oclIsTypeOf(JMM!Package)) {
+ t1.setValue(thisModule.stereotype, 'namespace', s1.
+ refImmediateComposite().getFullyQualifiedPackageName);
+ }
+ else {
+ t1.setValue(thisModule.stereotype, 'namespace', 'NOT_AVAILABLE');
+ }
+ }
+
+ -- TODO: nested classifiers are contained by classifiers rather than packages ;)
+ -- ... however nested
+ -- stereotypes are not actuall supported
+ else {
+ if(thisModule.resolveTemp(s1.refImmediateComposite(), 't1').
+ oclIsTypeOf(UMLMM!Package)) {
+ thisModule.resolveTemp(s1.refImmediateComposite(), 't1').packagedElement
+ <- t1;
+ }
+ else {
+ -- so let's get the package of the owner and put the stereotype there
+ -- ... however
+ -- there is a problem when we generate code !!!!
+ thisModule.resolveTemp(s1.refImmediateComposite().getJavaPackage(), 't1').
+ packagedElement <- t1;
+ }
+ }
+
+ -- if the target annotation is not set at all then we have to trigger a lazy rule
+ -- that produces extensions to
+ -- all possible candidates
+ if(not s1.proxy and not (s1.annotations -> exists(a | a.type.type.name =
+ 'Target'))) {
+ for(javaElementType in thisModule.umlTarget.getKeys()) {
+ for(umlElementType in thisModule.umlTarget.get(javaElementType)) {
+ thisModule.createExtension(s1, t1, umlElementType, javaElementType);
+ }
+ }
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule createExtension(annotationType: JMM!AnnotationTypeDeclaration, stereotype:
+ UMLMM!Stereotype,
+ metaClass: UMLMM!Element, elementType: String) {
+ to
+ -- the extension relationship
+ t1: UMLMM!Extension (
+ name <- 'extension_'.concat(stereotype.name).concat('_').concat(metaClass.
+ name),
+ memberEnd <- Sequence{t2, t3},
+ ownedEnd <- t3
+ ),
+ -- the properties of the relationship (end points)
+ t2: UMLMM!Property (
+ name <- 'base_'.concat(metaClass.name),
+ type <- metaClass,
+ -- we set the lower bound to 0 because if the stereotype extends
+ -- several metaclasses then we would get validation errors with
+ -- a lower bound 1
+ lower <- 0,
+ upper <- 1
+ ),
+ t3: UMLMM!ExtensionEnd (
+ name <- 'extension_'.concat(metaClass.name),
+ aggregation <- #composite,
+ type <- stereotype,
+ lower <- 0,
+ upper <- if(annotationType.isRepeatable) then (0-1) else 1 endif
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'createExtension',
+ targetElements <- Sequence{t1,
+ t2,
+ t3}
+ )
+ do {
+ -- refers to the ownedAttribute of the stereotype
+ stereotype.ownedAttribute <- t2;
+
+ -- refers to the profile that contains the stereotype
+ stereotype.refImmediateComposite().packagedElement <- t1;
+
+ -- if we create an extension of Type then we need a constraint as
+ -- UML:Type is more general then Java:Type
+
+ if(elementType = 'TYPE') {
+ thisModule.createTypeConstraint(stereotype);
+ }
+
+ else if(elementType = 'CONSTRUCTOR') {
+ thisModule.createConstructorConstraint(stereotype);
+ }
+
+ else if(elementType = 'METHOD') {
+ thisModule.createMethodConstraint(stereotype);
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{annotationType});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule SingleVariableAccessMultiValued2Extension {
+ from
+ s1: JMM!SingleVariableAccess (
+ s1.isMultiValuedAnnotationTarget
+ )
+ using {
+ s2: JMM!AnnotationTypeDeclaration = s1.refImmediateComposite().
+ refImmediateComposite().refImmediateComposite().refImmediateComposite();
+ }
+ to
+ -- the extension relationship
+ t1: UMLMM!Extension (
+ name <- 'extension_'.concat(thisModule.resolveTemp(s2, 't1').name).
+ concat('_').concat(thisModule.umlTarget.get(s1.variable.name).first().name),
+ memberEnd <- Sequence{t2,
+ t3},
+ ownedEnd <- t3
+ ),
+ -- the properties of the relationship (end points)
+ t2: UMLMM!Property (
+ name <- 'base_'.concat(thisModule.umlTarget.get(s1.variable.name).first().
+ name),
+ type <- thisModule.umlTarget.get(s1.variable.name).first(),
+ lower <- 0,
+ upper <- 1
+ ),
+ t3: UMLMM!ExtensionEnd (
+ name <- 'extension_'.concat(thisModule.umlTarget.get(s1.variable.name).
+ first().name),
+ aggregation <- #composite,
+ type <- thisModule.resolveTemp(s2, 't1')
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'SingleVariableAccessMultiValued2Extension',
+ targetElements <- Sequence{t1,
+ t2,
+ t3}
+ )
+ do {
+ -- refers to the ownedAttribute of the stereotype
+ thisModule.resolveTemp(s2, 't1').ownedAttribute <- t2;
+
+ -- refers to the profile that contains the stereotype
+ thisModule.resolveTemp(s2.getPackage(), 't1').packagedElement <- t1;
+
+ -- if the target is of type FIELD, we do have to create an extension for
+ -- EnumDeclaration as well;
+ -- if we use Associatons, we may have to add another extension
+ if(s1.variable.name = 'FIELD') {
+ thisModule.createExtension(s2, thisModule.resolveTemp(s2, 't1'), thisModule.
+ umlTarget.get(s1.variable.name).at(2), s1.variable.name);
+ }
+
+ -- if the target is of type METHOD, we do have to create an extension for
+ -- Property as well as methods in annotationtypedeclrations are translated
+ -- to property
+ if(s1.variable.name = 'METHOD') {
+ thisModule.createExtension(s2, thisModule.resolveTemp(s2, 't1'), thisModule.
+ umlTarget.get(s1.variable.name).at(2), s1.variable.name);
+ }
+
+ -- in case of TYPE we do have to create the type constraint
+ if(s1.variable.name = 'TYPE') {
+ thisModule.createTypeConstraint(thisModule.resolveTemp(s2, 't1'));
+ }
+
+ -- in case of CONSTRUCTOR we do have to create the type constraint
+ else if(s1.variable.name = 'CONSTRUCTOR') {
+ thisModule.createConstructorConstraint(thisModule.resolveTemp(s2, 't1'));
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule SingleVariableAccessSingleValued2Extension {
+ from
+ s1: JMM!SingleVariableAccess (
+ s1.isSingleValuedAnnotationTarget
+ )
+ using {
+ s2: JMM!AnnotationTypeDeclaration = s1.refImmediateComposite().
+ refImmediateComposite().refImmediateComposite();
+ }
+ to
+ -- the extension relationship
+ t1: UMLMM!Extension (
+ name <- 'extension_'.concat(thisModule.resolveTemp(s2, 't1').name).
+ concat('_').concat(thisModule.umlTarget.get(s1.variable.name).first().name),
+ memberEnd <- Sequence{t2,
+ t3},
+ ownedEnd <- t3
+ ),
+ -- the properties of the relationship (end points)
+ t2: UMLMM!Property (
+ name <- 'base_'.concat(thisModule.umlTarget.get(s1.variable.name).first().
+ name),
+ type <- thisModule.umlTarget.get(s1.variable.name).first(),
+ lower <- 0,
+ upper <- 1
+ ),
+ t3: UMLMM!ExtensionEnd (
+ name <- 'extension_'.concat(thisModule.umlTarget.get(s1.variable.name).
+ first().name),
+ aggregation <- #composite,
+ type <- thisModule.resolveTemp(s2, 't1')
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'SingleVariableAccessSingleValued2Extension',
+ targetElements <- Sequence{t1,
+ t2,
+ t3}
+ )
+ do {
+ -- refers to the ownedAttribute of the stereotype
+ thisModule.resolveTemp(s2, 't1').ownedAttribute <- t2;
+
+ -- refers to the profile that contains the stereotype
+ thisModule.resolveTemp(s2.getPackage(), 't1').packagedElement <- t1;
+
+ -- if the target is of type FIELD, we do have to create an extension for
+ -- EnumDeclaration as well;
+ -- if we use Associatons, we may have to add another extension
+ if(s1.variable.name = 'FIELD') {
+ thisModule.createExtension(s2, thisModule.resolveTemp(s2, 't1'), thisModule.
+ umlTarget.get(s1.variable.name).at(2), s1.variable.name);
+ }
+
+ -- if the target is of type METHOD, we do have to create an extension for
+ -- Property as well as methods in annotationtypedeclrations are translated
+ -- to property
+ if(s1.variable.name = 'METHOD') {
+ thisModule.createExtension(s2, thisModule.resolveTemp(s2, 't1'), thisModule.
+ umlTarget.get(s1.variable.name).at(2), s1.variable.name);
+ }
+
+ -- in case of TYPE we do have to create the type constraint
+ if(s1.variable.name = 'TYPE') {
+ thisModule.createTypeConstraint(thisModule.resolveTemp(s2, 't1'));
+ }
+
+ -- in case of CONSTRUCTOR we do have to create the type constraint
+ else if(s1.variable.name = 'CONSTRUCTOR') {
+ thisModule.createConstructorConstraint(thisModule.resolveTemp(s2, 't1'));
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+rule AnnotationTypeMemberDeclaration2Property {
+ from
+ s1: JMM!AnnotationTypeMemberDeclaration (
+ -- we need to exclude unresolved annotation type member declarations
+ if(s1.oclIsTypeOf(JMM!AnnotationTypeMemberDeclaration) and not s1.proxy) then
+
+ -- is a container stereotype required
+ ((s1.refImmediateComposite().isContainerAnnotation and s1.refImmediateComposite().requiresContainerAnnotation)
+ or not s1.refImmediateComposite().isContainerAnnotation)
+
+ or s1.refImmediateComposite().isRelevantForAnnotationTypes
+
+ else false
+ endif
+ )
+ to
+ t1: UMLMM!Property (
+ name <- s1.name,
+ -- can be set to public as no other visibility modifier is allowed for
+ -- annotation types
+ visibility <- #public,
+ -- the problem here is that we may have proxy member declaratios with no
+ -- further type information
+ type <- if (s1.type <> OclUndefined) then
+ s1.type.getType()
+ else
+ UMLMM!PrimitiveType.allInstancesFrom('EPT') -> select(e | e.name =
+ 'EJavaObject').first()
+ endif,
+ -- is done in post processing ;)
+ -- default <- if s1.default <> OclUndefined and
+ -- s1.default.oclIsTypeOf(JMM!NumberLiteral) then
+ -- s1.default.tokenValue else OclUndefined endif,
+ -- TODO: provide example for an undefined type
+ lower <- if s1.default <> OclUndefined then
+ 0
+ else
+ if s1.type <> OclUndefined then
+ if s1.type.type.oclIsTypeOf(JMM!ArrayType) then
+ 0
+ else
+ 1
+ endif
+ else
+ 1
+ endif
+ endif,
+ upper <- if s1.type <> OclUndefined then
+ if s1.type.type.oclIsTypeOf(JMM!ArrayType) then
+ -1
+ else
+ 1
+ endif
+ else
+ 1
+ endif,
+ -- if stereotypes are composed by other stereotypes
+ aggregation <- if s1.type <> OclUndefined
+ -- if the annotation member is of type Class then aggregation needs to be set to #none
+ then if(s1.type.isComplexType() and not s1.type.getType().oclIsTypeOf(UMLMM!Class)) then #composite else #none
+ endif
+ else #none
+ endif
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'AnnotationTypeMemberDeclaration2Property',
+ targetElements <- Sequence{t1}
+ )
+ do {
+
+ -- TODO : Here we should also consider the discussion about OCL constraints for
+ -- the allowed types as specified by the binding Class<T>
+ -- same as above: the problem here is that we may have proxy member declaratios
+ -- with no further type information
+ if(s1.type <> OclUndefined) {
+ if (s1.type.type.oclIsTypeOf(JMM!ParameterizedType)) {
+ thisModule.stereotype <- thisModule.getStereotypes -> any(e | e.name =
+ 'JGenericType');
+ t1.applyStereotype(thisModule.stereotype);
+
+ t1.setValue(thisModule.stereotype, 'type', 'upperBounded');
+
+ -- set the type of the 'binding' ... unbounded (default), upperbounded,
+ -- lowerbounded, bounded;
+ if (s1.type.type.typeArguments.first().type.
+ oclIsTypeOf(JMM!WildCardType)) {
+
+ -- if the type parameterized type is unresolved then create a proxy
+ -- element
+ -- design decision: it seems to be rather hard to express this part
+ -- declaratively ;(
+
+ if(not s1.type.type.typeArguments.first().type.bound.
+ oclIsUndefined()) {
+ if(s1.type.type.typeArguments.first().type.bound.type.
+ oclIsTypeOf(JMM!UnresolvedTypeDeclaration)) {
+
+ -- s1.refImmediateComposite().name.debug();
+ -- s1.name.debug();
+ thisModule.UnresolvedTypeDeclaration2Type(s1.type.type.
+ typeArguments.first().type.bound.type);
+ }
+ }
+
+ -- upperBounded case
+ if (s1.type.type.typeArguments.first().type.name.startsWith('?' + ''
+ + ' extends')) {
+ thisModule.stereotype <- thisModule.getStereotypes -> any(e | e.
+ name = 'JGenericType');
+ t1.setValue(thisModule.stereotype, 'type', 'upperBounded');
+
+ --t1.setValue(thisModule.stereotype, 'type', 'upperBounded');
+ --t1.setValue(thisModule.stereotype, 'parameter',
+ -- thisModule.resolveTemp(s1.type.type.typeArguments.first().type.bound.typ
+ -- e
+ -- ,
+ -- 't1').debug());
+ }
+ -- lowerBounded case
+ else if (s1.type.type.typeArguments.first().type.name.toString().
+ startsWith('? super')) {
+ t1.setValue(thisModule.stereotype, 'type', 'lowerBounded');
+ -- t1.setValue(thisModule.stereotype, 'parameter',
+ -- thisModule.resolveTemp(s1.type.type.typeArguments.first().type.bound.typ
+ -- e
+ -- ,
+ -- 't1').debug());
+ }
+ }
+
+ -- bounded case
+ else if (not s1.type.type.typeArguments.first().type.oclIsUndefined()) {
+
+ -- s1.name.debug();
+ t1.setValue(thisModule.stereotype, 'type', 'bounded');
+ t1.setValue(thisModule.stereotype, 'parameter', thisModule.
+ resolveTemp(s1.type.type.typeArguments.first().type,
+ 't1'));
+ }
+ }
+
+ if (s1.type.isComplexType()) {
+ thisModule.AnnotationTypeMemberDeclaration2Association(s1);
+ }
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+-- if we have UML properties with a complex type then we should create an UML association
+lazy rule AnnotationTypeMemberDeclaration2Association {
+ from
+ s1: JMM!AnnotationTypeMemberDeclaration
+ to
+ t1: UMLMM!Association (
+ name <- if (not s1.type.getType().name.oclIsUndefined()) then
+ s1.name.concat('_').concat(s1.refImmediateComposite().name).concat('_').concat(s1.type.getType().name)
+ else
+ s1.name.concat('_').concat(s1.refImmediateComposite().name).concat('_').concat(s1.type.type.name)
+ endif,
+ memberEnd <- s1,
+ memberEnd <- t2
+ ),
+ t2: UMLMM!Property (
+ -- the idea is to use the name of the Java field plus the classifier the
+ -- association points to
+ name <- s1.name.concat('_').concat(s1.refImmediateComposite().name),
+ -- can be set to public as no other visibility modifier is allowed for
+ -- annotation types
+ visibility <- #public,
+ -- TODO: Think about the multiplicity
+ lower <- 0,
+ upper <- 1,
+ type <- s1.refImmediateComposite()
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'AnnotationTypeMemberDeclaration2Association',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ thisModule.resolveTemp(s1.refImmediateComposite().getPackage(), 't1').
+ packagedElement <- t1;
+
+ -- case java.lang.Class / java.lang.Class[]: we do not want to change the
+ -- meta-class UML Class
+ -- so the produced property is contained by the association
+ if( (s1.type.type.oclIsTypeOf(JMM!ParameterizedType)) or
+ (s1.type.type.refImmediateComposite().getFullyQualifiedPackageName.toString().concat('.').concat(s1.type.type.name).toString()
+ = 'java.lang.Class') or ( -- in case the Array is parameterized the name
+ -- string also contains '<...>'
+ s1.type.type.name.toString().startsWith('java.lang.Class') and s1.type.
+ type.name.toString().endsWith('[]')) ) {
+
+ t1.ownedEnd <- t2;
+ }
+ -- we follow the standard procedure and put the produced property into the
+ -- associated element
+ else {
+ if(s1.type.type.oclIsTypeOf(JMM!ArrayType)) {
+
+ if(s1.type.type.elementType.type.
+ oclIsTypeOf(JMM!UnresolvedTypeDeclaration)) {
+ t1.ownedEnd <- t2;
+ }
+
+
+ thisModule.resolveTemp(s1.type.type.elementType.type, 't1').
+ ownedAttribute <- t2;
+ }
+ else {
+ thisModule.resolveTemp(s1.type.type, 't1').ownedAttribute <- t2;
+ }
+ }
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+
+ }
+}
+
+-- Refers to Types that cannot be resolved. This happens if a library references elements
+-- of another library for which we do not have access to the source. Then, we get only the
+-- type information and the type access but not further information.
+-- The idea is to transform those UnresolvedTypes that are used in the declaration of
+-- of annotations, i.e., AnnotationTypeMemberDeclarations. This seems to be essential
+-- to declare the AnnotationTypeMemberDeclaration.
+rule UnresolvedTypeDeclaration2Type {
+ from
+ s1: JMM!UnresolvedTypeDeclaration (
+ s1.usagesInTypeAccess -> exists(e | e.refImmediateComposite().
+ oclIsTypeOf(JMM!AnnotationTypeMemberDeclaration)) or
+ -- ArrayTypes need to be handled differently
+ s1.usagesInTypeAccess -> collect(e | e.refImmediateComposite()) ->
+ select(e | e.oclIsTypeOf(JMM!ArrayType)) -> exists(e | e.usagesInTypeAccess ->
+ exists(f | f.refImmediateComposite().oclIsTypeOf(JMM!AnnotationTypeMemberDeclaration)))
+ )
+ to
+ t1: UMLMM!Class (
+ name <- s1.name
+ ),
+ -- trace information
+ tl: TMM!TraceLink (
+ ruleName <- 'UnresolvedTypeDeclaration2Type',
+ targetElements <- Sequence{t1}
+ )
+ do {
+ if(thisModule.proxyPackage.oclIsUndefined()) {
+ thisModule -> initProxyPackage(s1);
+ }
+ thisModule.proxyPackage.packagedElement <- t1;
+
+ -- apply the proxy stereotype
+ thisModule.stereotype <- UMLMM!Stereotype.allInstancesFrom('JP') ->
+ select(e | e.name = 'JProxyType').first();
+ t1.applyStereotype(thisModule.stereotype);
+
+ -- trace information
+ tl.refSetValue('sourceElements', Sequence{s1});
+ thisModule.trace.traceLinks <- tl;
+ }
+}
+
+-- we do need a constraint for the Type extension as only Class, Interface, Enumeration
+-- and Stereotype
+-- should be targets for the produced Stereotype
+rule createTypeConstraint(stereotype: UMLMM!Stereotype) {
+ to
+ t1: UMLMM!Constraint (
+ name <- 'typeConstraint',
+ constrainedElement <- stereotype,
+ context <- stereotype,
+ specification <- t2
+ ),
+ t2: UMLMM!OpaqueExpression (
+ name <- 'typeConstraintExpression',
+ -- the type constraint
+-- body <- 'self.base_Type.oclIsUndefined() or
+-- (self.base_Type.oclIsTypeOf(uml::Class) or
+-- self.base_Type.oclIsTypeOf(uml::Interface) or
+-- self.base_Type.oclIsTypeOf(uml::Enumeration) or
+-- self.base_Type.oclIsTypeOf(uml::Stereotype))',
+ body <- 'not self.base_Type.oclIsUndefined() implies Set{uml::Stereotype,
+ uml::Class, uml::Enumeration, uml::Interface}
+ -> includes(self.base_Type.oclType())',
+ -- the language we use to express the constraint
+ language <- 'OCL'
+ )
+}
+
+-- furthermore, we do need a constraint for the Operation extension if the Java element
+-- type Constructor
+-- is used
+rule createConstructorConstraint(stereotype: UMLMM!Stereotype) {
+ to
+ t1: UMLMM!Constraint (
+ name <- 'constructorConstraint',
+ constrainedElement <- stereotype,
+ context <- stereotype,
+ specification <- t2
+ ),
+ t2: UMLMM!OpaqueExpression (
+ name <- 'constructorConstraintExpression',
+ -- the type constraint
+ -- body <- 'self.base_Operation.oclIsUndefined() or
+ -- self.base_Operation.name =
+ -- self.base_Operation.oclContainer().oclAsType(uml::Classifier).name'
+ -- ,
+ body <- 'not self.base_Operation.oclIsUndefined() implies
+ self.base_Operation.name =
+ self.base_Operation.oclContainer().oclAsType(uml::Classifier).name',
+ -- the language we use to express the constraint
+ language <- 'OCL'
+ )
+}
+
+-- since we translation methods of annotationtypedeclarations to properties, we do have
+-- to take care
+-- that such properties can be stereotyped if ElementType.Method is set
+rule createMethodConstraint(stereotype: UMLMM!Stereotype) {
+ to
+ t1: UMLMM!Constraint (
+ name <- 'methodConstraint',
+ constrainedElement <- stereotype,
+ context <- stereotype,
+ specification <- t2
+ ),
+ t2: UMLMM!OpaqueExpression (
+ name <- 'methodConstraintExpression',
+ -- the type constraint
+-- body <- 'self.base_Property.oclIsUndefined() or
+-- self.base_Property.oclContainer().oclIsTypeOf(uml::Stereotype)',
+ body <- 'not self.base_Property.oclIsUndefined() implies
+ self.base_Property.oclContainer().oclIsTypeOf(uml::Stereotype)',
+ -- the language we use to express the constraint
+ language <- 'OCL'
+ )
+}
+
+-- currently we do not use UML's support for templates and template binding!
+--rule ParameterizedType2Class {
+-- from
+-- s1 : JMM!ParameterizedType
+-- to
+-- t1 : UMLMM!Class (
+-- name <- s1.name,
+-- templateBinding <- s1.typeArguments
+-- )
+--}
+--
+--rule TypeAccessOfParameterizedType2TemplateBinding {
+-- from
+-- s1 : JMM!TypeAccess(
+-- if s1.refImmediateComposite().oclIsTypeOf(JMM!ParameterizedType)
+-- then s1.refImmediateComposite().typeArguments -> exists(e | e = s1)
+-- else false endif)
+-- to
+-- t1 : UMLMM!TemplateBinding (
+-- signature <-
+ -- s1.refImmediateComposite().getParameterizedClassFromJavaLibrary().ownedTemplateSignatur
+ -- e
+ -- ,
+ --
+-- parameterSubstitution <- t2
+-- ),
+--
+-- t2 : UMLMM!TemplateParameterSubstitution (
+-- -- TODO : the assumption here is that we have only one parameter
+-- formal <-
+ -- s1.refImmediateComposite().getParameterizedClassFromJavaLibrary().ownedTemplateSignature.ownedParameter.first(
+ -- )
+ -- ,
+ --
+-- actual <- if s1.type.oclIsTypeOf(JMM!AnnotationTypeDeclaration) then
+ -- s1.type else s1.getActualParameterFromModelLibrary() endif
+-- -- TODO : in RSA the property ownedActual is set as well ... but then the
+--- define step of UML2 plugin breaks!
+-- )
+--}

Back to the top