blob: 61c35bc78c4cd90242fec9bd91bb4773582c8ab6 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2011 Nicolas Deblock & Cedric Dumoulin & Manuel Giles.
*
*
* 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:
* Nicolas Deblock nico.deblock@gmail.com - Initial transformation and implementation
* Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial transformation and implementation
* Manuel Giles giles.manu@live.fr - Initial transformation and implementation
*
*****************************************************************************/
import stereotypeUtil;
/* Model type declarations
*/
modeltype UMLmm uses "http://www.eclipse.org/uml2/3.0.0/UML";
modeltype JDTmm uses 'http:///jdtmm.ecore';
modeltype GeneratorOptionsMM uses 'http:///GeneratorOptionsMM.ecore';
modeltype JavaProfile uses java('http://www.eclipse.org/papyrus/JAVA/1');
/**
*
*/
transformation uml2jdt2( in uml: UMLmm, in options : GeneratorOptionsMM, out jdt: JDTmm)
extends stereotypeUtil;
/** Root of java stereotypes */
intermediate property UMLmm::STEREOTYPE_JAVA_NAMED_ELEMENT : String;
intermediate property UMLmm::STEREOTYPE_JAVA_GEN : String;
/** Apply to any Types */
intermediate property UMLmm::STEREOTYPE_JAVA_CLASS : String;
intermediate property UMLmm::STEREOTYPE_JAVA_METHOD : String;
intermediate property UMLmm::STEREOTYPE_JAVA_PROPERTY : String;
intermediate property UMLmm::STEREOTYPE_JAVA_PROJECT : String;
intermediate property UMLmm::STEREOTYPE_JAVA_SRC_FOLDER : String;
intermediate property UMLmm::STEREOTYPE_JAVA_PACKAGE : String;
intermediate property UMLmm::STEREOTYPE_PRIMITIVETYPE : String;
intermediate property UMLmm::TAGVALUE_SRC : String;
intermediate property UMLmm::TAGVALUE_PROJECT : String;
intermediate property UMLmm::TAGVALUE_NAME : String;
intermediate property UMLmm::TAGVALUE_GENERATED : String;
intermediate property UMLmm::TAGVALUE_IMPLEMENTATION_CLASS : String;
intermediate property UMLmm::TAGVALUE_EXPLICIT_REQUIRED_IMPORTS : String;
intermediate property UMLmm::TAGVALUE_EXPLICIT_PLAIN_TEXT_REQUIRED_IMPORTS : String;
intermediate property UMLmm::NO_PACKAGE : String;
/** Default name values for generation */
intermediate property UMLmm::GENERATION_DEFAULT_SRC_NAME : String;
intermediate property UMLmm::GENERATION_DEFAULT_PROJECT_NAME : String;
/**
* The main operation. This is the entry point of the transformation.
*/
main() {
// Initialize global variables
uml.STEREOTYPE_JAVA_NAMED_ELEMENT := "java::JavaNamedElement";
uml.STEREOTYPE_JAVA_GEN := "java::JavaGen";
uml.STEREOTYPE_JAVA_CLASS := "java::JavaClass";
uml.STEREOTYPE_JAVA_METHOD := "java::JavaMethod";
uml.STEREOTYPE_JAVA_PROPERTY := "java::JavaProperty";
uml.STEREOTYPE_JAVA_PROJECT := "java::JavaProject";
uml.STEREOTYPE_JAVA_SRC_FOLDER := "java::JavaSrcFolder";
uml.STEREOTYPE_JAVA_PACKAGE := "java::JavaPackage_";
uml.STEREOTYPE_PRIMITIVETYPE := "java::PrimitiveType";
uml.TAGVALUE_SRC := "srcName";
uml.TAGVALUE_NAME := "name";
uml.TAGVALUE_GENERATED := "isGenerated";
uml.TAGVALUE_PROJECT := "projectName";
uml.TAGVALUE_IMPLEMENTATION_CLASS := "implementationClass";
uml.TAGVALUE_EXPLICIT_REQUIRED_IMPORTS := "explicitRequiredImports";
uml.TAGVALUE_EXPLICIT_PLAIN_TEXT_REQUIRED_IMPORTS := "explicitPlainTextRequiredImports";
uml.NO_PACKAGE := null;
// Default names
uml.GENERATION_DEFAULT_SRC_NAME := options.objectsOfType(GeneratorOptionsMM::Options)->asSequence()->first().defaultSourceFolder;
uml.GENERATION_DEFAULT_PROJECT_NAME := "defaultProject";
// Select only object that we want to generate
var types : Set(uml::Type) := uml.objects()[uml::Type]->select(o |
o.oclIsTypeOf(uml::Class)
or o.oclIsTypeOf(uml::Interface)
or o.oclIsTypeOf(uml::PrimitiveType)
or o.oclIsTypeOf(uml::Enumeration) );
log('------------------------ Start marking input elements');
// First pass: mark uml::Type objects
types -> map markUmlType(uml.GENERATION_DEFAULT_SRC_NAME, uml.GENERATION_DEFAULT_PROJECT_NAME);
// show result
log('------------------------ Show results');
types -> map showMarkedType();
log('------------------------ Show packages results');
uml.objects()[uml::Package] -> map showMarkedType();
// Second pass: transform marked objects
log('------------------------ Start transformation');
types -> map transformTypeToType();
log('------------------------ Done');
}
/**
* A query used to check if a stereotype is applied to an UML element
*/
query uml::Element::isStereotyped( stereotypeName : String ) : Boolean {
var stereotype = self.getAppliedStereotype(stereotypeName);
return not stereotype.oclIsUndefined();
}
/**
* Is the specified type a Compilation Unit ?
*/
query uml::Type::isCompilationUnit( ) : Boolean {
// A compilation unit is a type whose owner is a Package
return self.owner.oclIsKindOf(Package);
}
/**
* Get the interfaces associated to the Classifier
*/
query uml::Classifier::generalInterfaces() : Set(uml::Interface) {
// Get interface linked by a generalization
// var res : Set(uml::Interface) := self.generalization -> select( p | p.general.oclIsTypeOf(uml::Interface))
// -> collect(p | p.general.oclAsType(uml::Interface)) -> asSet();
var res : Set(uml::Interface) := self.generalization.general[uml::Interface] -> asSet();
return res;
}
/**
* Get the class associated to a stereotype. This work for static profile.
*/
query uml::NamedElement::getStereotype(stereotypeName:String) : OclAny {
var stereotype := self.getAppliedStereotype(stereotypeName);
if (stereotype.oclIsUndefined())
then
return null
endif;
return self.getStereotypeApplication(stereotype);
}
/**
* Get the JavaClass stereotype from a classifier.
*/
query uml::Classifier::getJavaClassStereotype() : JavaProfile::JavaClass {
return self.getStereotype(uml.STEREOTYPE_JAVA_CLASS).oclAsType(JavaProfile::JavaClass);
}
/**
* Get the JavaClass stereotype from a classifier.
*/
query uml::Operation::getJavaMethodStereotype() : JavaProfile::JavaMethod {
return self.getStereotype(uml.STEREOTYPE_JAVA_METHOD).oclAsType(JavaProfile::JavaMethod);
}
/**
* Get the JavaClass stereotype from a classifier.
*/
query uml::Property::getJavaPropertyStereotype() : JavaProfile::JavaProperty {
return self.getStereotype(uml.STEREOTYPE_JAVA_PROPERTY).oclAsType(JavaProfile::JavaProperty);
}
/**
* Get the ExplicitImports from a classifier.
* Explicit imports are stored in a Stereotype.
*/
query uml::Classifier::getExplicitPlainTextRequiredImports() : Set(String) {
var emptySet : Set(String) := Set{};
return self.getTaggedValue( uml.STEREOTYPE_JAVA_CLASS,
uml.TAGVALUE_EXPLICIT_PLAIN_TEXT_REQUIRED_IMPORTS,
OclAny ) [String]->asSet();
}
/**
* Get the interfaces associated to the Classifier
*/
query uml::BehavioredClassifier::generalInterfacesForClass() : Set(uml::Interface)
{
// Get interface linked by a generalization
// var res : Set(uml::Interface) := self.generalization -> select( p | p.general.oclIsTypeOf(uml::Interface))
// -> collect(p | p.general.oclAsType(uml::Interface)) -> asSet();
var res : Set(uml::Interface) := self.generalization.general[uml::Interface] -> asSet();
// manage the interfaceRealisation
res += self.oclAsType(uml::BehavioredClassifier).interfaceRealization.supplier[uml::Interface];
return res;
}
/**
* Get the general Class associated to the Enumeration
*/
query uml::Enumeration::general() : uml::Class {
// Get interface linked by a generalization
var res : uml::Class := self.generalization.general[uml::Class] -> asOrderedSet() -> first();
return res;
}
/**
* return true if the element is marked has "toGenerate". Return false otherwise.
*/
query uml::NamedElement::isGenerated() : Boolean {
// by default, generated are true
var generated := true;
self.getApplicableStereotypes()->forEach(st) {
generated := self->getBooleanTaggedValue("java::"+st.name, "isGenerated",generated)->asOrderedSet()->first();
};
return generated;
}
/**
* Compute additional data associated to self.
* How to compute such datas is dependant of the type of self, so dispatch to the appropriate method.
*
* Common ancestor. Dispatch to correct method according to the element's type.
*/
helper NamedElement::getData(defaultSrcName : String, defaultProjectName : String) : TypeMarker {
// log("NamedElement::getData(self.name=" + self.name + ") ");
// overloading doesn't work, so we do it manually
if( self.oclIsKindOf(uml::PrimitiveType)) then {
return self.oclAsType(uml::PrimitiveType).getDataFromPrimitiveType( defaultSrcName, defaultProjectName);
} endif;
if( self.oclIsKindOf(uml::Type)) then {
return self.oclAsType(uml::Type).getDataFromType( defaultSrcName, defaultProjectName);
}
else {
if( self.oclIsKindOf(uml::Package)) then {
return self.oclAsType(uml::Package).getDataFromPackage( defaultSrcName, defaultProjectName);
} endif;
} endif;
// not defined
return null;
}
/**
* Compute the additional data for a uml::Type.
* Recursively set the additional data for the parent (owner) of this type.
*/
helper Type::getDataFromType( defaultSrcName : String, defaultProjectName : String) : TypeMarker {
log( "Type::getDataFromType(self.name=" + self.name + ")");
// Check if data already exist
if not self.data.oclIsUndefined()
then
return self.data
endif;
// Create it
log("Type::getData() - start creation");
var data : TypeMarker := object TypeMarker {};
var parent :uml::Namespace := self.namespace;
if parent != null
then {
//
var parentData : TypeMarker := parent.getData(defaultSrcName, defaultProjectName);
data.srcName := self.getStringTaggedValue(uml.STEREOTYPE_JAVA_CLASS, uml.TAGVALUE_SRC, parentData.srcName);
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_CLASS, uml.TAGVALUE_PROJECT, parentData.projectName );
data.packageName := parentData.packageName;
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_CLASS, uml.TAGVALUE_GENERATED, true );
}
else {
data.srcName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_CLASS, uml.TAGVALUE_SRC, defaultSrcName );
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_CLASS, uml.TAGVALUE_PROJECT, defaultProjectName );
data.packageName := uml.NO_PACKAGE;
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_CLASS, uml.TAGVALUE_GENERATED, true );
}
endif;
self.data := data;
return data;
}
/**
* Compute the additional data for a uml::Type.
* Recursively set the additional data for the parent (owner) of this type.
*
* Primitive types are stored in the package declared in uml.TAGVALUE_IMPLEMENTATION_CLASS.
* If no implementation class is declared, use the same scheme as Classes.
*/
helper PrimitiveType::getDataFromPrimitiveType( defaultSrcName : String, defaultProjectName : String) : TypeMarker {
log("Type::getDataFromPrimitiveType(self.name=" + self.name + ")");
// Check if data already exist
if not self.data.oclIsUndefined()
then
return self.data
endif;
// Create it
log("Type::getData() - start creation");
var data : TypeMarker := object TypeMarker {};
var parent :uml::Namespace := self.namespace;
if parent != null
then {
//
var parentData : TypeMarker := parent.getData(defaultSrcName, defaultProjectName);
data.srcName := self.getStringTaggedValue(uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_SRC, parentData.srcName);
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_PROJECT, parentData.projectName );
data.packageName := parentData.packageName;
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_GENERATED, parentData.generated );
}
else {
data.srcName := self.getStringTaggedValue( uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_SRC, defaultSrcName );
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_PROJECT, defaultProjectName );
data.packageName := uml.NO_PACKAGE;
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_GENERATED, true );
}
endif;
// Check if an instance name is set
var instanceClassName := self.getStringTaggedValue(uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_IMPLEMENTATION_CLASS, null);
if( not instanceClassName.oclIsUndefined()) then {
// Try to get the package name from the provided qualified name.
// If none is specified, use the regular package name.
var packageName : String := instanceClassName.findPackageFromQualifiedName(data.packageName);
data.packageName := packageName;
} endif;
self.data := data;
return data;
}
/**
* Get the package name of the specified qualifiedname. Return the package name if there is one.
* Return the nameIfNotFound value if no package is set in qualifiedName.
* @param nameIfNotFound Default name returned if no package specified in provided String
*/
query String::findPackageFromQualifiedName( nameIfNotFound : String) : String {
// Get the index of the last segment
var cur : int := self.lastIndexOf('.');
// return empty string if not found
var res : String;
// Do strange comparison because of trouble with
// QVTo
if 0>(cur) then {
res := nameIfNotFound;
}
else {
res := self.substring( 1, cur);
} endif;
return res;
}
/**
* Get the last name from the specified qualifiedname.
*/
query String::lastNameFromQualifiedName( ) : String {
// Get the index of the last segment
var cur : Integer := self.lastIndexOf('.');
// return empty string if not found
var res : String;
// Do strange comparison because of trouble with
// QVTo
if 0>(cur) then {
// Only one name ==> return it
res := self;
}
else {
cur := cur+2;
res := self.substring( cur, self.size());
} endif;
return res;
}
/**
* Get generation data associated to a Package.
* Associated stereotype are taken into account to compute the GenData
*/
helper Package::getDataFromPackage(defaultSrcName : String, defaultProjectName : String) : TypeMarker {
log("Type::getDataFromPackage(self.name=" + self.name + ")");
// Check if data already exist
if not self.data.oclIsUndefined()
then
return self.data
endif;
var data : TypeMarker;
// Switch to correct helper, according to stereotype
switch {
case (self.isStereotyped( uml.STEREOTYPE_JAVA_SRC_FOLDER) ) {
// SrcFolder
data := self.createDataFromSrcFolder(defaultSrcName, defaultProjectName);
}
case ( self.isStereotyped( uml.STEREOTYPE_JAVA_PROJECT) ) {
// JavaProject
data := self.createDataFromJavaProject(defaultSrcName, defaultProjectName);
}
case ( self.isStereotyped( uml.STEREOTYPE_JAVA_PACKAGE)) {
// Treat it as a Java Package
// uml::Model and uml::Package can be marked with this stereotype.
// When a uml::Model is marked as package, it is not considered anymore as a root for packages
data := self.createDataFromSimplePackage(defaultSrcName, defaultProjectName);
}
case ( self.oclIsTypeOf(uml::Model) ) {
// uml::Model
// uml::Model is considered as the root of packages.
// So, stop on type Model, except if a STEREOTYPE_JAVA_PACKAGE is set.
data := self.createDataFromUmlModel(defaultSrcName, defaultProjectName);
}
else {
// Default Package
data := self.createDataFromSimplePackage(defaultSrcName, defaultProjectName);
}
};
self.data := data;
return data;
}
/**
* Get or create the Data for a Package Stereotypes "SrcFolder"
*/
helper Package::createDataFromSrcFolder(defaultSrcName : String, defaultProjectName : String) : TypeMarker {
var data := object TypeMarker {};
var parent : Namespace := self.namespace;
if parent != null
then {
//
var parentData : TypeMarker := parent.getData(defaultSrcName, defaultProjectName);
// We are in an SrcFolder, so srcName is either the stereotype.srcName or self.name
data.srcName := self.getStringTaggedValue(uml.STEREOTYPE_JAVA_SRC_FOLDER, uml.TAGVALUE_SRC, self.name);
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_SRC_FOLDER, uml.TAGVALUE_PROJECT, parentData.projectName );
// packageName = "" or null, as we are in a srcFolder (root of packages)
data.packageName := uml.NO_PACKAGE;
// Compute generated: (parent.generated == false ? false : taggedValue || true )
data.generated := if parentData.generated = false then false else self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_SRC_FOLDER, uml.TAGVALUE_GENERATED, true ) endif;
}
else {
data.srcName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_SRC_FOLDER, uml.TAGVALUE_SRC, self.name );
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_SRC_FOLDER, uml.TAGVALUE_PROJECT, defaultProjectName );
// packageName = "" or null, as we are in a srcFolder (root of packages)
data.packageName := uml.NO_PACKAGE;
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_SRC_FOLDER, uml.TAGVALUE_GENERATED, true );
}
endif;
// self.data := data;
return data;
}
/**
* Get or create the Data for this simple Package
* Don't check if the package is a src or project
*/
helper Package::createDataFromSimplePackage(defaultSrcName : String, defaultProjectName : String) : TypeMarker {
var data := object TypeMarker {};
var parent : Namespace := self.namespace;
if parent != null
then {
//
var parentData : TypeMarker := parent.getData(defaultSrcName, defaultProjectName);
data.srcName := self.getStringTaggedValue(uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_SRC, parentData.srcName);
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_PROJECT, parentData.projectName );
data.packageName := self.computePackageName( parentData.packageName, self.getStringTaggedValue(uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_NAME, self.name) );
data.generated := if parentData.generated = false then false else self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_GENERATED, true ) endif;
}
else {
// This is the root node, and maybe the stereotype overide some values.
data.srcName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_SRC, defaultSrcName );
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_PROJECT, self.name );
data.packageName := self.getStringTaggedValue(uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_NAME, self.name);
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_PACKAGE, uml.TAGVALUE_GENERATED, true );
}
endif;
// self.data := data;
return data;
}
/**
*
*/
helper Package::computePackageName( parentName : String, selfName : String) : String {
if( parentName.oclIsUndefined() or parentName.length() = 0) then {
return selfName;
} endif;
return parentName + "." + selfName;
}
/**
* Get or create the Data for a Package Stereotypes "Project"
*/
helper Package::createDataFromJavaProject(defaultSrcName : String, defaultProjectName : String) : TypeMarker {
var data := object TypeMarker {};
data.srcName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_PROJECT, uml.TAGVALUE_SRC, defaultSrcName );
// We are in a JavaProject, so the name is either the setereotype.projectName, or the folder name
data.projectName := self.getStringTaggedValue( uml.STEREOTYPE_JAVA_PROJECT, uml.TAGVALUE_PROJECT, self.name );
// packageName = "" or null, as we are in a srcFolder (root of packages)
data.packageName := uml.NO_PACKAGE;
data.generated := self.getBooleanTaggedValue( uml.STEREOTYPE_JAVA_PROJECT, uml.TAGVALUE_GENERATED, true );
return data;
}
/**
* Get or create the Data for a uml::Model with no stereotype
* This is the root, so stop recursivity
*/
helper Package::createDataFromUmlModel(defaultSrcName : String, defaultProjectName : String) : TypeMarker {
var data := object TypeMarker {};
data.srcName := defaultSrcName;
// Use the name of the Model as project name.
data.projectName := self.name;
// packageName = "" or null, as we are in a srcFolder (root of packages)
data.packageName := uml.NO_PACKAGE;
data.generated := true;
return data;
}
/**
* A class used to hold data on a type
*/
intermediate class TypeMarker {
isCompilationUnit : Boolean;
projectName : String;
srcName : String;
packageName : String;
generated : Boolean = true;
}
// log this object
query TypeMarker::show() : String {
return self.projectName + "-" + self.srcName + "-" + self.packageName;
/*
+ "(isCu=" + self.isCompilationUnit.repr()
+ ", isGenerated=" + self.generated.repr()
+ ")";
*/
};
/**
* Add a property to the uml::Type. This property is filled during the first pass.
* The first pass collect the data that are used during the second pass.
*/
intermediate property uml::NamedElement::data : TypeMarker;
/**
* Show the content of marked type
*/
mapping uml::NamedElement::showMarkedType()
{
log( '--------- ' + self.name + " ---------");
log( 'uml=' + self.repr());
log( 'data=' + self.data.repr());
log( 'projectName=' + self.data.projectName);
log( 'srcName =' + self.data.srcName.repr());
log( 'packageName=' + self.data.packageName);
log( 'generated =' + self.data.generated.repr());
}
/**
* Map a model to a JavaModel.
* Compute and associate additional data (in a TypeMarker class) to the type.
* Recursively ensure that the data are associated to the container of this type.
*/
mapping uml::Type::markUmlType(defaultSrcName : String, defaultProjectName : String)
// when { self.isCompilationUnit() }
{
// log("------ try to get data for " + self.name);
if( self.data.oclIsUndefined() ) then {
log("Compute associated data for '" + self.name + "'");
self.data := self.getData( defaultSrcName, defaultProjectName);
} endif;
}
/**
* Map a model to a JavaModel.
* Compute and associate additional data (in a TypeMarker class) to the type.
* Recursively ensure that the data are associated to the container of this type.
*/
mapping uml::Type::markUmlType()
{
self.map markUmlType( uml.GENERATION_DEFAULT_SRC_NAME, uml.GENERATION_DEFAULT_PROJECT_NAME);
}
/**
*
*/
mapping uml::Namespace::getNamespaceMarker() : TypeMarker {
init {
// if not self.namespaceMarker.oclIsUndefined() then return self.namespaceMarker endif;
}
}
/* ******************************************************************** */
/* */
/* ******************************************************************** */
abstract mapping uml::NamedElement::transformNamedElementToJavaElement() : JDTmm::JDTJavaElement
{
// by default, isGenerated are true
generated := self.isGenerated();
//generated := self.data.generated;
comment := self.ownedComment.body->asOrderedSet()->first();
log("************************************" + self.name,comment);
}
mapping uml::Type::transformTypeToType() : JDTmm::JDTType
disjuncts Class::generateCuClass, Class::generateNestedClass,
Interface::generateCuInterface, Interface::generateNestedInterface,
Enumeration::generateCuEnumeration, Enumeration::generateNestedEnumeration,
PrimitiveType::generateCuPrimitiveType
{
}
helper createOrRetrieveJavaModel2() : JDTJavaModel {
// get the model unique instance, or create it.
var model : JDTJavaModel := resolveoneIn(createOrRetrieveJavaModel).oclAsType(JDTJavaModel);
if( model.oclIsUndefined()) then {
model := map createOrRetrieveJavaModel();
} endif;
return model;
}
/**
* Generate a Class that should be a CompilationUnit and set its CompilationUnit
*/
mapping uml::Class::generateCuClass() : JDTmm::JDTClass
inherits Class::generateClass /*, NamedElement::transformNamedElementToJavaElement */
when { self.isCompilationUnit() }
{
log("------- transform", self.qualifiedName);
compilationUnit := self.map type2CompilationUnit();
}
/**
* Generate a Class that is nested in another Type
*/
mapping uml::Class::generateNestedClass() : JDTmm::JDTClass
inherits Class::generateClass
when { not self.isCompilationUnit() }
{
log("------- transform", self.qualifiedName);
// We are NOT a compilation unit, so our parent is a Type
owner := self.namespace.oclAsType(uml::Type).map transformTypeToType();
}
/**
* Generate a Class.
* set all except its compilationUnit and its owner
*/
mapping uml::Class::generateClass() : JDTmm::JDTClass
inherits Classifier::mapTypeToType
{
// log( "Interfaces:");
// self.generalInterfaces()->forEach(c) {
// log( " interface=", c.name);
// };
log("------- transform", self.qualifiedName);
interface := false;
_class := true;
_enum := false;
// map inheritance
superClass := self.superClass[uml::Class] -> asOrderedSet() -> first().map transformTypeToType();
// map interfaces
superInterfaces := self.generalInterfacesForClass() -> map transformTypeToType();
// Properties
fields := self.ownedAttribute.map propertyToField();
// Compute property from associations
// This is already computed from the previous case, as such
// properties are marked with owner=Classifier
// fields += self.ownedAttribute.map propertyToAssociationField();
fields += self[uml::AssociationClass].memberEnd.map propertyToFieldOfAssociationClass();
//fields.type := self->generateClass() -> asOrderedSet() -> first();
// Methods
methods := self.ownedOperation -> map operationToMethod();
}
/**
* Create a Compilation Unit, and set its packageFragment
*/
mapping uml::Type::type2CompilationUnit() : JDTCompilationUnit
inherits NamedElement::transformNamedElementToJavaElement
{
elementName := self.name;
// Compute the package fragment from the GenData associated to the type
var res : JDTPackageFragment := self.data.map typeMarkerToPackageFragment();
// log( "try to set package fragment found packageFragment=", res);
// log( " type(.packageFragment)=", self);
// Set the packageFragment of this CU
// next call has a bug, so we do the opposite affectation:
// add this CU to its packageFragment
// packageFragment := res;
res.compilationUnits += result;
}
/**
* Generate a Interface that should be a CompilationUnit and set its CompilationUnit
*/
mapping uml::Interface::generateCuInterface() : JDTmm::JDTInterface
inherits Interface::generateInterface /*, NamedElement::transformNamedElementToJavaElement */
when { self.isCompilationUnit() }
{
log("------- transform", self.qualifiedName);
compilationUnit := self.map type2CompilationUnit();
}
/**
* Generate a Interface that is nested in another Type
*/
mapping uml::Interface::generateNestedInterface() : JDTmm::JDTInterface
inherits Interface::generateInterface
when { not self.isCompilationUnit() }
{
log("------- transform", self.qualifiedName);
// We are NOT a compilation unit, so our parent is a Type
owner := self.namespace.oclAsType(uml::Type).map transformTypeToType();
}
/**
* Generate a Interface.
* set all except its compilationUnit and its owner
*/
mapping uml::Interface::generateInterface() : JDTmm::JDTInterface
inherits Classifier::mapTypeToType
{
interface := true;
_class := false;
_enum := false;
// map interfaces
superInterfaces := self.generalInterfaces() -> map transformTypeToType();
// Properties
fields := self.ownedAttribute -> map propertyToField();
// Methods
methods := self.ownedOperation -> map operationToMethod();
}
/**
* Generate a Enumeration that should be a CompilationUnit and set its CompilationUnit
*/
mapping uml::Enumeration::generateCuEnumeration() : JDTmm::JDTEnum
inherits Enumeration::generateEnumeration /*, NamedElement::transformNamedElementToJavaElement */
when { self.isCompilationUnit() }
{
log("------- transform", self.qualifiedName);
compilationUnit := self.map type2CompilationUnit();
}
/**
* Generate a Enumeration that is nested in another Type
*/
mapping uml::Enumeration::generateNestedEnumeration() : JDTmm::JDTEnum
inherits Enumeration::generateEnumeration
when { not self.isCompilationUnit() }
{
log("------- transform", self.qualifiedName);
// We are NOT a compilation unit, so our parent is a Type
owner := self.namespace.oclAsType(uml::Type).map transformTypeToType();
}
/**
* Generate a Enumeration.
* set all except its compilationUnit and its owner
*/
mapping uml::Enumeration::generateEnumeration() : JDTmm::JDTEnum
inherits Classifier::mapTypeToType
{
interface := false;
_class := false;
_enum := true;
// map inheritance
superClass := self.general().map transformTypeToType();
// map interfaces
superInterfaces := self.generalInterfaces() -> map transformTypeToType();
// Properties
fields := self.ownedAttribute -> map propertyToField();
// Litterals ??
fields += self.ownedLiteral -> map enumerationLiteral2Field();
// Methods
methods := self.ownedOperation -> map operationToMethod();
}
mapping uml::EnumerationLiteral::enumerationLiteral2Field() : JDTmm::JDTField
{
elementName := self.name;
// visibility
visibility := self.visibility.visibilityToVisibility();
// modifiers
final := false;
_static := false;
// multiplicity
isMultiValued := false;
// type
type := null;
}
/**
* Generate a primitive type
*/
mapping uml::PrimitiveType::generateCuPrimitiveType() : JDTmm::JDTClass
inherits Classifier::mapTypeToType
{
log("------- transform", self.qualifiedName);
compilationUnit := self.map type2CompilationUnit();
// Compute elementName
// Check if another name is set in instanceClassname
// Set only the last name, because the package name is set previously in the compilationUnit.
var instanceName : String := self.getStringTaggedValue(uml.STEREOTYPE_PRIMITIVETYPE, uml.TAGVALUE_IMPLEMENTATION_CLASS, null);
elementName := if( instanceName.oclIsUndefined())
then self.name
else instanceName.lastNameFromQualifiedName()
endif;
// Adjust compilation unit name
compilationUnit.elementName := elementName;
generated := self.data.generated;
}
/**
* Generate a Enumeration.
* set all except its compilationUnit and its owner
*/
abstract mapping uml::Classifier::mapTypeToType() : JDTmm::JDTType
inherits NamedElement::transformNamedElementToJavaElement
{
// Ensure that data are set
if( self.data.oclIsUndefined()) then {
self.map markUmlType();
} endif;
elementName := self.name;
// visibility
visibility := self.visibility.visibilityToVisibility();
// modifiers
_abstract := self.getBooleanTaggedValue("java::JavaClass", "isAbstract",self.isAbstract);
final := self.getBooleanTaggedValue("java::JavaClass", "isFinal",self.isLeaf);
_static := self.getBooleanTaggedValue("java::JavaClass", "isStatic", false);
generated := self.data.generated;
// Explicit imports
explicitRequiredImports += self.elementImport.target[uml::Classifier] -> map transformTypeToType();
// Explicit imports from stereotype
var ext:JavaProfile::JavaClass := self.getJavaClassStereotype();
if( ext <> null) then {
explicitRequiredImports += ext.explicitRequiredImports -> map transformTypeToType();
explicitPlainTextRequiredImports += ext.explicitPlainTextRequiredImports
} endif;
}
/**
* Transform the visibility.
*/
query uml::VisibilityKind::visibilityToVisibility() : jdtmm::VisibilityKind {
if( self = uml::VisibilityKind::public ) then return jdtmm::VisibilityKind::public endif;
if( self = uml::VisibilityKind::protected ) then return jdtmm::VisibilityKind::protected endif;
if( self = uml::VisibilityKind::private ) then return jdtmm::VisibilityKind::private endif;
// Can't happen'
return jdtmm::VisibilityKind::public;
}
/**
* Map a Property to a field
*/
mapping uml::Property::propertyToField() : JDTField
inherits NamedElement::transformNamedElementToJavaElement
{
//
elementName := self.name;
// visibility
visibility := self.visibility.visibilityToVisibility();
// modifiers
final := self.getBooleanTaggedValue("java::JavaProperty", "isFinal",self.isLeaf);
_static := self.getBooleanTaggedValue("java::JavaProperty", "isStatic", self.isStatic);
// getter setter
generateGetter := self.getEnumTaggedValue("java::JavaProperty", "generateGetter", "default").getTrueFalseDefaultValue();
generateSetter := self.getEnumTaggedValue("java::JavaProperty", "generateSetter", "default").getTrueFalseDefaultValue();
// multiplicity
isMultiValued := self.upper < 1;
// type
type := self.type.map transformTypeToType();
// Specify the default value
if(not self.defaultValue.isNull() ) then {
value := self.defaultValue.valueSpecificationToString();
} endif;
// Explicit imports from stereotype
var ext:JavaProfile::JavaProperty := self.getJavaPropertyStereotype();
if( ext <> null) then {
explicitRequiredImports += ext.explicitRequiredImports -> map transformTypeToType();
explicitPlainTextRequiredImports += ext.explicitPlainTextRequiredImports
} endif;
}
/**
* Compute the default value from the ValueSpecification.
* Check if this is a special case.
*
*/
query uml::ValueSpecification::valueSpecificationToString() : String {
switch {
case (self.oclIsTypeOf(uml::InstanceValue)) {
var iv := self.oclAsType(uml::InstanceValue );
// Is it an EnumLiteral ?
if( iv.instance.oclIsTypeOf(uml::EnumerationLiteral)) then {
// This is an enum literal. Prefix it with its typeName
return iv.type.name + "." + iv.instance.name;
} endif;
}
else {
return self.stringValue()
}
};
return "";
}
/**
* Return the value of the enumeration literal for Enum 'TrueFalseDefault'
*/
query String::getTrueFalseDefaultValue(): TrueFalseDefault {
if(self = "true") then
return TrueFalseDefault::_true
else
if(self = "false") then
return TrueFalseDefault::_false
endif
endif;
return TrueFalseDefault::_default;
}
/**
* Map a Property to a field of a association class
*/
mapping uml::Property::propertyToFieldOfAssociationClass() : JDTField
inherits Property::propertyToField
{
}
/**
* Map a Property to a association field assoc+nameOfProperty
*/
mapping uml::Property::propertyToAssociationField() : JDTField
inherits Property::propertyToField
when {
not self.association.oclIsUndefined()
}
{
// handle the class association
elementName := "assoc"+ self.name.firstToUpper();
type := self.association.map transformTypeToType()->asOrderedSet()->first();
}
/**
* Map a Operation to a Method
*/
mapping uml::Operation::operationToMethod() : JDTMethod
inherits NamedElement::transformNamedElementToJavaElement
{
//
elementName := self.name;
// visibility
visibility := self.visibility.visibilityToVisibility();
// modifiers
final := self.getBooleanTaggedValue("java::JavaMethod", "isFinal",self.isLeaf);
_static := self.getBooleanTaggedValue("java::JavaMethod", "isStatic", self.isStatic);
_abstract := self.getBooleanTaggedValue("java::JavaMethod", "isAbstract", self.isAbstract);
synchronized := self.getBooleanTaggedValue("java::JavaMethod", "isSynchronized", false);
// constructor
_constructor := self.getBooleanTaggedValue("java::JavaMethod", "isConstructor", false);
// arguments
returnType := self.ownedParameter->select(m| m.direction.repr()="return")->first().map parameterToParameter();
parameters := self.ownedParameter->select(m| m.direction.repr()!="return")-> map parameterToParameter();
// Body
bodies := self.method -> map BehaviorToMethodBody();
// exception
exceptions := self.raisedException -> map transformTypeToType();
// Explicit imports from stereotype
var ext:JavaProfile::JavaMethod := self.getJavaMethodStereotype();
if( ext <> null) then {
explicitRequiredImports += ext.explicitRequiredImports -> map transformTypeToType();
explicitPlainTextRequiredImports += ext.explicitPlainTextRequiredImports
} endif;
}
mapping uml::Parameter::parameterToParameter() : jdtmm::JDTParameter
inherits NamedElement::transformNamedElementToJavaElement
{
//
elementName := self.name;
// modifiers
final := self.getBooleanTaggedValue("java::JavaClass", "isFinal",false);
// multiplicity
isMultiValued := self.upper < 1;
// type
type := self.type.map transformTypeToType();
}
/**
* Transform a Behavior to a JDTMethodBody.
* Root rule of transforming a Behavior to a JDTMethodBody. The real transformation ois done in sub-rules
* (with the same name, but different input type).
*
* Behavior can't be transformed to JDTMethodBody, so create a JDTMethodBody with an error message.
*/
mapping uml::Behavior::BehaviorToMethodBody() : jdtmm::JDTMethodBody {
init {
var jdtBody := object JDTOpaqueBody {};
jdtBody._body := "Don't know how to map a Behavior to a Java Body";
result := jdtBody;
}
}
/**
* Transform an OpaqueBehavior to a MethodBody.
* As we return a subclass of JDTMethodBody, delegate to the appropriate rule.
*/
mapping uml::OpaqueBehavior::BehaviorToMethodBody() : jdtmm::JDTMethodBody {
init {
result := self.map OpaqueBehaviorToOpaqueBody();
}
}
/**
* Transform an OpaqueBehavior to a OpaqueBody
*/
mapping uml::OpaqueBehavior::OpaqueBehaviorToOpaqueBody() : jdtmm::JDTOpaqueBody {
// log("OpaqueBehavior found");
// Look for the java index
var index : Integer := self.language->indexOf("Java");
if ( index >= 0) then {
_body := self.body->at(index);
}
else {
_body := "// No 'Java' body found. Please set a 'Java' body in the OpaqueBehavior associted to method.";
}
endif;
}
/**
* Get or create the PackageFragment corresponding to the TypeMarker
*/
mapping TypeMarker::typeMarkerToPackageFragment() : JDTPackageFragment {
init {
// Check if the fragment already exist
// First, lookup fragment root
var srcRoot:JDTPackageFragmentRoot := self.map typeMarkerToPackageFragmentRoot();
// Second, lookup in srcRoot for an fragment with the same name
result := srcRoot.packageFragments -> select( fragment | self.packageName=fragment.elementName)-> asSequence()-> first();
if( result.oclIsUndefined()) then {
log("create fragment " + self.packageName );
}
else {
log("reuse fragment '" + result.elementName + "'' for gendata " + self.show() );
} endif;
// Ideally, we should return here. But this is not allowed in this qvt version
// return;
}
// Initialize our object if it is not already done
if( packageFragmentRoot.oclIsUndefined() ) then {
// Try one of the end of the relation. Some QVT implementation fail on the first end,
// So use the second. (In any cases, we should only affect one end, EMF will do the second end)
// packageFragmentRoot := srcRoot; // self.map typeMarkerToPackageFragmentRoot();
srcRoot.packageFragments += result;
elementName := self.packageName;
// Get the isGenerated Flag
// Need to know the flag that has been set in the corresponding package.
// But here, we only got the genData associated to the CompilationUnit, so we
// can't know the flag value.
// TODO: improve the algorithm to be able to get the package's flag value
// actually, always set it to true
generated := true;
/*
// if package is generated=false, put generated=false for the children's package
if(generated = false) then {
log("c'est false");
srcRoot.packageFragments->forEach(pack) {
log("**********************"+pack.elementName, pack.elementName.indexOf(elementName));
if (pack.elementName.indexOf(elementName) != -1) then {
pack.generated := false;
log("************************ elementName pass� � ", generated);
} endif;
};
} endif;
*/
} endif;
}
/**
* Get or create the PackageFragmentRoot corresponding to the TypeMarker
*/
mapping TypeMarker::typeMarkerToPackageFragmentRoot() : JDTPackageFragmentRoot {
init {
// Check if the fragment already exist
// First, lookup corresponding project
var project:JDTJavaProject := self.map typeMarkerToJavaProject();
// Second, lookup in project for an srcRoot with the same name
result := project.packageFragmentRoots -> select( srcRoot | self.srcName=srcRoot.elementName)-> asSequence()-> first();
if( result.oclIsUndefined()) then {
log("create PackageFragmentRoot " + self.srcName );
}
else {
log("reuse PackageFragmentRoot '" + result.elementName + "' for gendata " + self.show() );
} endif;
// Ideally, we should return here. But this is not allowed in this qvt version
// return;
}
// Initialize our object if it is not already done
if( javaProject.oclIsUndefined() ) then {
javaProject := project; // self.map typeMarkerToJavaProject();
elementName := self.srcName;
// Get the isGenerated Flag
// Need to know the flag that has been set in the corresponding package.
// But here, we only got the genData associated to the CompilationUnit, so we
// can't know the flag value.
// TODO: improve the algorithm to be able to get the package's flag value
// actually, always set it to true
generated := true;
} endif;
}
/**
* Get or create the PackageJavaProject corresponding to the TypeMarker
*/
mapping TypeMarker::typeMarkerToJavaProject() : JDTJavaProject {
init {
// Lookup if there is a Project already created for this projectName
// resolveIn return a list of object created with the specified mapping rule
// Then, we loukup in the list for an element with the requested name.
result := resolveIn(TypeMarker::typeMarkerToJavaProject)
->select( project | self.projectName=project.oclAsType(JDTJavaProject).elementName)->first().oclAsType(JDTJavaProject);
if( result.oclIsUndefined()) then {
log("create project " + self.projectName );
}
else {
log("reuse project '" + result.elementName + "'' for gendata " + self.show() );
} endif;
// Ideally, we should return here. But this is not allowed in this qvt version
// return;
}
// Initialize our object if it is not already done
if( javaModel.oclIsUndefined() ) then {
javaModel := map createOrRetrieveJavaModel();
elementName := self.projectName;
// Get the isGenerated Flag
// Need to know the flag that has been set in the corresponding package.
// But here, we only got the genData associated to the CompilationUnit, so we
// can't know the flag value.
// TODO: improve the algorithm to be able to get the package's flag value
// actually, always set it to true
generated := true;
} endif;
}
/**
*
*/
mapping createOrRetrieveJavaModel () : JDTJavaModel {
init {
// result := resolveoneIn(createOrRetrieveJavaModel).oclAsType(JDTJavaModel);
// if not result.oclIsUndefined() then{ return c; }endif;
}
generated := true;
elementName := "JavaModel";
}