PyEmofUCProyecto ejemplo CountyCityJ.M. Drake, P. López Martínez y C. CuevasGrupo de
Ingeniería Software y Tiempo Real (ISTR)
- Universidad
de Cantabria
|
PyEmofUC => Carpeta raíz
que resulta al desempaquetar el fichero
PyEmofUC_0_0.zip. Es el origen de los path
relativos. CountyCity => Carpeta raíz del ejemplo CountyCity que se utiliza para mostrar las capacidades de PyEmofUC. DumpedFiles => Carpeta contenedora de los ficheros que se generan en la demostración. Su contenido puede ser eliminado. Metamodels => Carpeta contenedora de ,os metamodelos (M2) del ejemplo. City.xmi => Formulación XMI del metamodelo City. City.xsd => Schema para asistir la introducción de modelos conformes al metamodelo City. County.xmi => Formulación XMI del metamodelo County. County.xsd => Schema para asistir la introducción de modelos conformes al metamodelo County. TaxCensus.xmi => Formulación XMI del metamodelo TaxCensus. TaxCensus.xsd => Schema para asistir la introducción de modelos conformes al metamodelo TaxCensus. Models => Carpeta contenedora de los modelos (M1) del ejemplo. eagleCity.xmi => Ejemplo de instancia de un modelo conforme al metamodelo City. eagleCounty.xmi => Ejemplo de instancia de un modelo conforme al metamodelo County. Scripts => Carpeta contenedora de los scripts ejecutables del ejemplo. CountyCity_CountyToTaxCensus_Declarative_Script.py => Script de demostración de una transformación M2M con estilo declarativo. CountyCity_CountyToTaxCensus_Imperative_Script.py => Script de demostración de una transformación M2M con estilo imperativo. CountyCity_LoadDump_Script.py => Script que muestra un proceso de carga/procesamiento/serialización de un modelo. schema => Carpeta contendora de W3C-schemas de propósito general requeridos por el entorno PyEmofUC para tareas auxiliares. EMOF.xsd => Schema del metametamodelo EmofUC. Referenciado para validación XML por las formulaciones XMI de los metamodelos. XMI.xsd => Schema de especificación de la extensión XMI de OMG. Es importado por las formulaciones XMI de los metamodelos. src => Carpeta raíz del código Python del entorno PyEmofUC. Su path es incluido en la variable de entorno PYTHONPATH. |
import
pyEmofUC.resource as resource import
pyEmofUC.xmlcore as xmlcore import
pyEmofUC.GLOBAL as GLOBAL xmlcore.PLATFORM
= 'C:\CountyCityWorkspace' # Set
VERBOSE MODE GLOBAL.IS_VERBOSE
= True # CountyCity
metamodel URIs countyURI = "http://unican.es/istr/PyEmofUC/CountyCity/County" cityURI = "http://unican.es/istr/PyEmofUC/CountyCity/Cyty" # The
application repository is built aRep =
resource.AppRepository() # Loads the
EagleCity model eagleCounty_URL
= "platform:CountyCity/models/EagleCounty.xmi" eagleCounty =
aRep.loadModel(eagleCounty_URL) # Example of
model managing: Displays the loaded models print '\n' + 'PRINTS
LIST
OF LOADED MODELS:' for
loadedModelURI in aRep.mdlRepositories.keys(): print 5 * ' ' +
loadedModelURI # Example of
model processing: List the name of adults without
job print '\n' + 'PRINT
LIST
OF ADULTS WITHOUT JOB:' adultWithoutJob
= (adult for home in eagleCounty.rootPackage.home
for adult in home.member
if adult.isInstanceOf('cnty.Adult') and not adult.job) for theAdult in
adultWithoutJob: print 5 * ' ' +
theAdult.name # Dumps
eagleCounty model with RTF format dumpedEagleCounty_URL
= 'platform:CountyCity/DumpedFiles/EagleCounty.rtf' eagleCounty.dump(dumpedEagleCounty_URL) # Delete all
models del aRep |
# @nsURI
county_MM=http://unican.es/istr/PyEmofUC/CountyCity/County # @nsURI taxCensus_MM=
http://unican.es/istr/PyEmofUC/CountyCity/TaxCensus module County_To_TaxCensus; create outTaxCensusModel
: taxCensus_MM from inCountyModel
: county_MM; helper def :
rootContainer() : county_MM!County = . . .; helper def :
currentDate() : String = . . .; helper def :
accumulatedSalary(theAdult: county_MM!Adult) : Real= . . .; lazy rule createTax
{ from theAdult
: county_MM!Adult to theTax
: TaxCensus!Tax ( amount <- (0.2 * accumulatedSalary(theAdult)) – (100.0
* len(theAdult.offspring)), date <- thisModule.currentDate() ) } entrypoint rule County_To_TaxCensus
() { to theCountyTaxCensus
: taxCensus_MM!CountyTaxCensus( countyName <- thisModule.rootContainer().countyName, taxPayer <- thisModule.rootContainer().home -> collect(theHome |
theHome.member -> select(theMember |
theMember.isInstanceOf(County_MM!Adult)) ) ) } rule Adult_To_TaxPayer
{ from theAdult
: county_MM!Adult to theTaxPayer
: taxCensus_MM!TaxPayer ( payerName <- theAdult.name, address <- theAdult.home.address+
’ ‘ + thisModule.rootContainer().countyAddress, currentTax <- if
not theAdult.job
-> isEmpty() then thisModule.createTax(theAdult), else OclUndefined
endif, holder <- theAdult } |
County_MM reprenta el URI del
metamodelo County taxCensus_MM representa el URI del mm
TaxCensus El modulo County_To_TaxCensus
representa la generación del modelo
outTaxCensusModel a partir de del modelo
inCountyModel Retorna el elemeto contenedor raiz
del modelo de entrada. Retorna la
fecha del momento
que se invoca. Retona el
salatio acumulado de un eleemnto Adult como la
suma de los salarios de los job que tiene
asignados. Regla invocable que genera un
elemento de tipo Tax en el modelo de salida en
base a los datos de un element Adult del fichero
de entrada Regla inicial que genera un element
contenedor raíz del modelo de salida en base al
modelo de entrada. Regla que genera un element TaxPayer
en el modelo de salida or cada element Adult del
modelo de entrada. |
Código Python |
Código ATL |
||
import emofUC.resource as resource import emofUC.xmlcore as xmlcore import emofUC.GLOBAL as GLOBAL aRep
= resource.AppRepository() xmlcore.PLATFORM = "C:\Users\. .
.\PyEMOF_UC\Workspace" |
|
||
|
@path
county_MM_URL= platform:CountyCity/County.xmi @ path
taxCensus_MM_URL= platform:CountyCity/TaxCensus.xmi |
||
county_MM_URL = 'platform:CountyCity/County.xmi' taxCensus_MM_URL
= 'platform:CountyCity/TaxCensus.xmi' aRep.loadModel(taxCensus_MM_URL) |
|
||
|
module CountyCity_To_TaxCensus; create outTaxCensusModel : taxCensus_MM from inCountyModel : county_MM; |
||
outTaxCensusModelURI = "http://unican.es/istr/PyEmofUC/CountyCity/EagleTaxCensus" outTaxCensusModelNsPrefix
= 'etxc' outTaxCensusModel
= aRep.createMdlRepository(uri=outTaxCensusModelURI,
mmUrl=taxCensus_MM_URL,
nsPrefix=outTaxCensusModelNsPrefix) inCountyModelURL
= "platform:CountyCity/EagleCounty.xmi" inCountyModel = aRep.loadModel(inCountyModelURL) |
|
||
|
helper def :
rootContainer() : county_MM!County = . . .; |
||
def rootContainer(): return inCountyModel.rootPackage |
|
||
|
helper def :
currentDate() : String = . . .; |
||
def currentDate(): return GLOBAL.currentDate() |
|
||
|
helper def :
accumulatedSalary(theAdult: county_MM!Adult) : Real= .
. .; |
||
def accumulatedSalary(theAdult): return reduce(lambda x, y:x +
y, [job.salary for job in theAdult.job]) |
|
||
|
lazy rule createTax
{ from theAdult
: county_MM!Adult to theTax
: TaxCensus!Tax ( amount <- (0.2 * accumulatedSalary(theAdult)) – (100.0
* len(theAdult.offspring)), date <- thisModule.currentDate() ) } |
||
def createTax(theAdult): if len(theAdult.job)
> 0: theTax
= outTaxCensusModel.createElement('txc.Tax',
theAdult.xmi_id.replace('cnty', 'etxc') + '.theTax') theTax.amount
= (0.2 *
accumulatedSalary(theAdult)) - (100.0 *
len(theAdult.offspring)) theTax.date
= currentDate() return theTax else: return None |
|
||
|
entrypoint rule County_To_TaxCensus
() { to theCountyTaxCensus
: taxCensus_MM!CountyTaxCensus( countyName <- thisModule.rootContainer().countyName, taxPayer <- thisModule.rootContainer().home -> collect(theHome |
theHome.member -> select(theMember |
theMember.isInstanceOf(County_MM!Adult)) ) ) } |
||
theCounty
= rootContainer() theCountyTaxCensus
= outTaxCensusModel.createElement('txc.CountyTaxCensus',
rootContainer().xmi_id.replace('cnty', 'etxc')) theCountyTaxCensus.countyName
= rootContainer().countyName theCountyTaxCensus.taxPayer = [theMember.xmi_id.replace('cnty', 'etxc') + '.theTaxPayer' for theHome in rootContainer().home for theMember intheHome.member if theMember.isInstanceOf('cnty.Adult')] |
|
||
|
rule Adult_To_TaxPayer
{ from theAdult :
county_MM!Adult to theTaxPayer :
taxCensus_MM!TaxPayer ( payerName <- theAdult.name, address <- theAdult.home.address+
’ ‘ + thisModule.rootContainer().countyAddress, currentTax <- thisModule.createTax(theAdult), holder <- theAdult } |
||
for theAdult in (theAdult for theAdult in inCountyModel.getElements() if theAdult.isInstanceOf('cnty.Adult')): theTaxPayer
= outTaxCensusModel.createElement('txc.TaxPayer',
theAdult.xmi_id.replace('cnty', 'etxc') + '.theTaxPayer') theTaxPayer.payerName
= theAdult.name theTaxPayer.address
= theAdult.home.address + ' ' +
inCountyModel.rootPackage.countyAddress theTaxPayer.holder
= theAdult theTaxPayer.currentTax = createTax(theAdult) |
|
||
|
#Actualización de las referencias
entre los objetos creados en el modelo de salida |
||
outTaxCensusModel.rootPackage
= theCountyTaxCensus theCountyTaxCensus.taxPayer = [outTaxCensusModel.getElement(xmiid)
for xmiid in theCountyTaxCensus.taxPayer] |
|
El resultado de la transformación puede verse
en el fichero EagleTaxCensus_Declarative.xmi.
Formulación de la transformación con estilo imperativo.
En la siguiente tabla se describe la transformación County_To_TaxCensus con un estilo imperativo. El algoritmo de transformación se formula mediante un pseudocódigo basado en el recorrido de los elementos del modelo de entrada y en la creación y agregación de los correspondientes elementos del modelo en base a condicionales que evalúan las condiciones de guarda, y evaluación de atributos.
1. Crea un repositorio
de aplicación para dar soporte a la transformación
de modelos. 2. Abre el fichero de
entrada y lo carga en el repositorio de la
aplicación. 3. Carga el metamodelo
del modelo de salida 4. Crea un modelo de
salida vacío 5. Crea el elemento
contenedor raíz del modelo de salida. 5.1. Asigna valor a los
atributos 5.2. FOR cada elemento Adult
del modelo de entrada crea un TaxPayer en el modelo
de salida. 5.2.1. Asigna valor a los
atributos del elemento TaxPayer creado. 5.2.2. IF el elemento Adult
tiene trabajos referenciados en el campo job: 5.2.2.1. Crea un elemento Tax
y asigna los valores a los atributos. 5.2.2.2. Agrega el elemento creado (o None si no
se creado) al elemento TaxPayer |
Código Python |
Seudocódigo |
||
|
1. Crea un repositorio de
aplicación para dar soporte a la transformación de
modelos. |
||
import emofUC.resource as resource import emofUC.xmlcore as xmlcore import emofUC.GLOBAL as GLOBAL aRep
= resource.AppRepository() xmlcore.PLATFORM = "C:\Users\. .
.\PyEMOF_UC\Workspace" |
|
||
|
2. Abre el fichero de entrada y
lo carga en el repositorio de la aplicación. |
||
inCountyModelURL = "platform:CountyCity/EagleCounty.xmi" inCountyModel = aRep.loadModel(inCountyModelURL) |
|
||
|
3. Carga el metamodelo del
modelo de salida |
||
taxCensus_MM_URL = 'platform:CountyCity/TaxCensus.xmi' |
|
||
|
4. Crea un
modelo de salida vacío |
||
aRep.loadModel(taxCensus_MM_URL) outTaxCensusModelURI
= "http://unican.es/istr/PyEmofUC/CountyCity/EagleTaxCensus" outTaxCensusModelNsPrefix
= 'etxc' outTaxCensusModel
= aRep.createMdlRepository( uri=outTaxCensusModelURI, mmUrl=taxCensus_MM_URL, nsPrefix=outTaxCensusModelNsPrefix) |
|
||
|
5. Crea
el elemento contenedor raíz del modelo de salida. |
||
rootContainer_xmiid = 'etxc.Id_' +
str(outTaxCensusModel.nextXmiId()) theCountyTaxCensus
= outTaxCensusModel.createElement( metaclass='txc.CountyTaxCensus', xmi_id=rootContainer_xmiid) outTaxCensusModel.rootPackage
= theCountyTaxCensus |
|
||
|
5.1 Asigna
valor a los atributos |
||
theCountyTaxCensus.countyName =
inCountyModel.rootPackage.countyName |
|
||
|
5.2 FOR cada elemento Adult del modelo
de entrada crea un TaxPayer en el modelo de salida |
||
for theAdult in (theAdult for theAdult in inCountyModel.getElements() if theAdult.isInstanceOf('cnty.Adult')): |
|
||
|
5.2.1.
Asigna valor a los atributos del elemento TaxPayer
creado |
||
theTaxPayer
= outTaxCensusModel.createElement('txc.TaxPayer', 'etxc.Id_' + str(outTaxCensusModel.nextXmiId())) theTaxPayer.payerName
= theAdult.name theTaxPayer.address
= theAdult.home.address + ' ' +
inCountyModel.rootPackage.countyAddress theTaxPayer.holder = theAdult |
|
||
|
5.2.2. IF el
elemento Adult tiene trabajos referenciados en el
campo job: |
||
theTax
= None if len(theAdult.job)
> 0: |
|
||
|
5.2.2.1. Crea
un elemento Tax y asigna los valores a los
atributos. |
||
theTax
= outTaxCensusModel.createElement('txc.Tax', 'etxc.Id_' + str(outTaxCensusModel.nextXmiId())) theTax.amount
= -100.0 *
len(theAdult.offspring) for theJob in theAdult.job: theTax.amount
+= 0.2 *
theJob.salary theTax.date = GLOBAL.currentDate() |
|
||
|
5.2.2.2. Agrega
el elemento creado (o None si no se creado) al
elemento TaxPayer |
||
theTaxPayer.currentTax
= theTax theCountyTaxCensus.taxPayer.append(theTaxPayer) |
|