Download Curso DSDM Sesión 4 - Genereración de código

Document related concepts
no text concepts found
Transcript
Curso DSDM
Sesión 4 - Genereración de código (MOFScript)
Grupo Modelum
Universidad de Murcia
10 de marzo de 2009
Resumen
En esta sesión se abordará la fase de generación de código utilizando el lenguaje
MOFScript. MOFScript es un lenguaje de plantillas basado en reglas que permite generar
código a partir de modelos conformes a metamodelos. Su simplificidad y facilidad para
definir plantillas lo convierte en un lenguaje comprensible y muy potente.
Durante este guión se continuará desarrollando el ejemplo tratado durante los guiones
anteriores. En esta sesión el objetivo será generar código a partir de los modelos que han
resultado de la transformación modelo a modelo de la sesión anterior.
1
1.
Introducción
En la sesión anterior se aplicaron una serie de transformaciones modelo a modelo para
obtener un modelo intermedio que representa una pequeña arquitectura para gestionar menús
a partir del modelo de sintaxis abstracta del DSL. El objetivo de esta sesión es generar el
código necesario para la incorporación de un menú en una aplicación Swing a partir del
modelo intermedio generado.
Para llevar a cabo la generación de código, se utilizará el lenguaje de transformación
MOFScript, el cual es un lenguaje basado en reglas integrado en la plataforma Eclipse. Una
transformación MOFScript está compuesta por un conjunto de reglas que definen las secciones
de código a generar a partir de los elementos del modelo origen. Estas secciones a generar
actúan como plantillas donde se inserta determinada información para completarlas, por este
motivo, MOFScript también recibe el nombre de lenguaje de plantillas. Durante el desarrollo
de este guión se presentará el entorno de programación en MOFScript y se desarrollará la
transformación necesaria. En el Anexo A puede encontrarse un resumen de las principales
sentencias de MOFScript.
2.
Sesión guiada
2.1.
Organización del proyecto para el DSL
Se parte del proyecto menuprofile desarrollado durante el guión de la sesión anterior.
Para el trabajo que se realizará en este guión, se creará una carpeta llamada m2c dentro de
la carpeta transformations (si no existe ya). Esta será nuestra carpeta de trabajo, todas
las transformaciones MOFScript que se realicen se guardarán en su interior. En un principio
se trabajará con una sola definición de transformación.
Durante el desarrollo de este guión se generará una aplicación Java Swing que será la que
incorporará el menú correspondiente a cada perfil. Por ello es necesario crear un proyecto
Java donde se almacenarán los ficheros generados como resultado de la ejecución de la transformación MOFScript. Al integrar la generación del código en un proyecto Java de Eclipse
se puede utilizar el sistema de compilación automática de la plataforma ası́ como su entorno
de edición y depuración.
2.1.1.
Tareas
1. Crear una carpeta llamada m2c dentro de la carpeta transformations.
2. La estructura del proyecto se muestra en la Figura 1.
3. Crear un fichero MOFScript con el nombre de menu2swing.m2t.
4. Crear un proyecto Java llamado menuprofile.gen.
2.1.2.
Resumen de comandos
Click der. (proyecto) → New folder → Nombre de carpeta
Crear nueva carpeta
Click der. (Carpeta m2c) → New. . . → Other → MOFScript →
MOFScript File
Crear nuevo fichero MOFScript
2
Figura 1: Estructura de las carpetas del proyecto menuprofiles
1
File → New. . . → Java Project
Crear nuevo proyecto Java
2.2.
Configuración del entorno
MOFScript está incorporado a la plataforma Eclipse como un plugin que ofrece un editor
para transformaciones MOFScript, un motor para la ejecución de transformaciones y una hoja
de configuración en el menú de preferencias de Eclipse. Antes de comenzar a definir y ejecutar
transformaciones MOFScript, es conveniente comprobar que la información contenida en la
hoja de configuración es correcta.
La hoja de configuración que ofrece MOFScript puede observarse en la Figura 2. El campo
principal a comprobar es el primero, el cual indica la localización de los metamodelos que se
utilizarán en la definición de las transformaciones. De todas formas, es conveniente comprobar
que los demás campos contienen información correcta para evitar problemas colaterales. Para
ello, se debe hacer click en cada campo y comprobar si existe mensaje de error.
Figura 2: Hoja de configuración de MOFScript
Una cuestión importante a destacar es el hecho de que si trabajamos con metamodelos
3
almacenados en diferentes partes del disco deberı́amos cambiar este campo de configuración
continuamente. La solución a este problema es utilizar el registro de metamodelos ecore en la
plataforma Eclipse. Con este método, podemos registrar un metamodelo y las transformaciones que utilicen dicho metamodelo funcionarán correctamente sin la necesidad de configurar
el plugin en la hoja de configuración.
La configuración del directorio donde se almacenarán los ficheros generados como resultado de una transformación MOFScript se debe realizar individualmente para cada fichero
m2t. La Figura 3 muestra la hoja de propiedades asociada a cada fichero m2t.
Otra forma de configurar la ejecución de la transformación MOFScript es haciendo uso
de la tarea Ant encargada de dicha finalidad. Para ello, se debe crear un fichero build.xml
(o reutilizar el ya existente en el proyecto) y añadir un elemento de tipo target que configure
la tarea MOFScript para llevar a cabo la ejecución.
Figura 3: Propiedades MOFScript para un fichero m2t
2.2.1.
Tareas
1. Abrir la hoja de configuración del plugin MOFScript.
2. Comprobar que los datos de los campos son correctos.
3. Configurar la propiedad Select Root Output Directory de la hoja de propiedades MOFScript para el fichero menu2swing.m2t. Esta propiedad debe indicar la ruta hacia el
directorio src del proyecto menuprofile.gen.
2.2.2.
Resumen de comandos
Windows → Preferences → MOFScript Preferences
Abrir la hoja de configuración del plugin MOFScript
Click der. (fichero Ecore) → Register metamodel
Registrar metamodelo
Click der. (fichero m2t) → Properties → MOFScript properties
Configurar propiedades MOFScript para un fichero m2t
4
2.3.
Conocimiento del dominio de la arquitectura destino
La transformación MOFScript que se desarrollará en este guión generará el código necesario para incluir un menú en una aplicación Swing a partir de una instancia del metamodelo
de la arquitectura. En primer lugar, se debe conocer el dominio donde se generará el código.
Swing es una librerı́a gráfica en Java que forma parte de Java Foundation Classes (JFC).
Incluye un conjunto de elementos gráficos (o widgets) tales como cajas de texto, botones,
menús o tablas para llevar a cabo el diseño y creación de aplicaciones de interfaz gráfica en
Java.
Una aplicación Swing puede tener incluido un menú que contiene un conjunto de opciones
para interacturar con la aplicación. La clase principal encargada de representar el menú en una
aplicación es JMenuBar, la cual puede contener un conjunto de elementos de tipo JMenuItem.
En la Figura 4 se muestra la jerarquı́a de estos elementos de menú.
Figura 4: Jerarquı́a de clases para los menús en Swing
El código Java que incluye un menú File con las opciones New y Close en una aplicación
App serı́a el siguiente:
// Creacion de menus
JMenu fileMenu = new JMenu("File");
fileMenu.add(new JMenuItem("New"));
fileMenu.add(new JMenuItem("Close"));
// Creacion de barra de menu
JMenuBar menuBar = new JMenuBar();
menuBar.add(fileMenu);
// Creacion de ventana e inclusin de barra de menu
JFrame app = new JFrame("App");
app.setJMenuBar(menuBar);
Durante el desarrollo de este guión, se construirá una aplicación Java Swing que incorpore una barra de menú. La organización de los elementos contenidos en dicha barra de
menú será dependiente del perfil que esté activo. Por lo tanto, debe existe una forma para
realizar el cambio de perfiles. Para llevar a cabo la creación de la aplicación se ha optado por
crear dos clases:
Clase Application. Esta clase es una aplicación Swing que incluye la barra de menú y
permite cambiar entre los diferentes perfiles. El cambio de perfiles se realiza por medio
de la pulsación del botón correspondiente incluido en dicha aplicación. El código de
ejemplo para esta clase se muestra en el Anexo C.
Clase MenuManager. Es la clase encargada de construir los menús correspondientes a
los perfiles. Es utilizada por Application para recuperar el menú asociado a un perfiles
al pulsar el botón correspondiente. El código de ejemplo para esta clase se muestra en
el Anexo D.
5
A continuación, se abordará la generación de estas clases utilizando el lenguaje MOFScript.
2.4.
Generar el esqueleto de Application
Al igual que se harı́a para crear la aplicación de manera tradicional, el primer paso consistirı́a en generar una aplicación Java Swing de prueba que incorpore el menú o menús
correspondientes a cada perfil. De esta forma, el proceso a seguir para definir la transformación MOFScript consistirá primero en generar la clase Java encargada de mostrar la ventana
(llamada Application) y a continuación generar la clase encargada de gestionar los menús
(llamada MenuManager).
El primer paso para definir una transformación MOFScript es especificar su nombre y el
metamodelo que utilizará para definir las reglas de transformación. Se parte del metamodelo
generado por la transformación modelo-a-modelo definida en la sesión anterior. La finalidad
principal de este metamodelo es acercarse al dominio de la arquitectura destino y facilitar
con ello la generación de código. El metamodelo se muestra en el Anexo B.
A continuación se debe definir la regla main de la transformación. Como en la mayorı́a de
los casos, la regla main de la transformación tendrá como contexto el elemento raı́z del metamodelo, que es MenuManager, el cual representa a la entidad encargada de crear y gestionar
los menús. A partir de dicho elemento se puede acceder a los menus y los profiles definidos.
La regla main se encargará de crear el fichero que contendrá a la clase Application, la
cual se encargará de visualizar una ventana en pantalla. El código esqueleto a generar para
mostrar una ventana en Java Swing serı́a el siguiente:
package centic;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import
import
import
import
javax.swing.BoxLayout;
javax.swing.JButton;
javax.swing.JFrame;
javax.swing.JPanel;
public class Application {
public static void main(String[] args) throws IOException {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Application theInstance = new Application();
((Application) theInstance).createAndShowGUI();
}
});
}
public void createAndShowGUI() {
// Create and set up the window.
final JFrame frame = new JFrame("Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPane = new JPanel();
BoxLayout layout = new BoxLayout(mainPane, BoxLayout.Y_AXIS);
mainPane.setLayout(layout);
frame.setContentPane(mainPane);
// Show the window.
frame.pack();
frame.setVisible(true);
}
}
6
2.4.1.
Tareas
1. Crear una regla main en la transformación main2swing que genere el código Java anterior. Se debe tener en cuenta que la clase Application debe estar contenida en el paquete
centic.
2. Probar la generación de código y comprobar que la clase Application funciona correctamente
2.5.
Generar los botones de cambio de menú en Application
El siguiente paso consistirı́a en enriquecer el código Java de la clase Application para que
muestre un botón por cada perfil de menú que esté definido en el metamodelo. La pulsación
de cada uno de ellos provocarı́a que la aplicación Java Swing cambie la disposición de los
menús.
El código especı́fico para la inclusión de menús en la aplicación está asociado a las acciones
asociadas a los botones que incluirá la aplicación Swing. En concreto, el código Java que
realizarı́a estas acciones serı́a el siguiente
JButton ProfileButton = new JButton("Profile");
ProfileButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setJMenuBar(MenuManager.INSTANCE.getProfile() );
frame.pack();
}
});
mainPane.add(ProfileButton);
Como se puede observar, el código anterior debe repetirse para cada tipo de perfil que se
haya definido. Además, el punto de variabilidad del código se encuentra en el nombre que se
da a la variable JButton, el texto que incluye el botón, ası́ como la llamada al método get
de la clase MenuManager.
Con estas modificaciones, la definición de transformación MOFScript genera el código
necesario para la clase Application. La implementación de dicha transformación se incluye
en el Anexo E.
2.5.1.
Tareas
1. Enriquecer la regla main para que contemple la generación de código para los botones.
2. Probar la generación de código y comprobar que la clase Application funciona correctamente.
2.6.
Generar el código para MenuManager
Al igual que para la clase Application, la regla main se encargará también de generar
la clase MenuManager, la cual se encargará de crear los menús. El código que debe generar
la regla main debe ser estudiado para conocer cuales son los puntos que dependen de la
información del modelo de arquitectura. La clase MenuManager (un ejemplo de dicha clase
puede encontrarse en D) se descompone en las siguientes secciones:
1. Declaración del paquete en el que está incluida la clase.
2. Sección de imports.
3. Declaración de la clase.
a) Variables de instancia.
7
b) Constructor de la clase.
c) Constructor de los elementos del menú.
d ) Establecimiento de las acciones para los elementos del menú.
e) Constructores de las barras de menú para los perfiles.
De las secciones anteriores, las únicas que dependen de la información contenida en los
modelos de la arquitectura las siguientes:
Sección 1. El nombre del paquete debe poder ser cambiado.
Sección 3a. Las variables de instancia dependen de los elementos de menú que contenga
el modelo.
Sección 3c. El constructor para los elementos del menú depende del número y tipo de
elementos que contenga el modelo.
Sección 3d. La acción asociada a cada elemento del menú depente de la información del
modelo.
Sección 3e. Se debe generar un constructor de barra de menú para cada perfil.
Una vez identificadas las partes del código dependientes de la información del modelo,
se puede pasar a la definición de la regla main encargada de la generación del código para
la clase MenuManager. A continuación se estudiará el código a incluir en cada una de las
secciones dependiente de la información del modelo.
Sección 1. Generación del paquete. Esta sección es simple y simplemente debe
hacerse uso de una propiedad de la definición de transformación para generar el codigo.
Sección 3a. Generación de las variables de instancia. Esta sección de la clase
MenuManager contiene tantas variables de instancia como elementos del menú contenga la instancia de la metaclase MenuManager, en concreto, la referencia menus. Esta
referencia es de tipo MenuItem, que realmente es una jerarquı́a de metaclases que representan a diferentes tipos de menú, por lo que el código a generar para cada una de
ellas difiere. Las correspondencias entre cada metaclase y el objeto Java Swing que lo
representa como menú son las siguientes:
Metaclase arquitectura
SingleMenuItem
TreeMenu
MenuBar
CheckboxMenuItem
Objeto Java Swing
JMenuItem
JMenu
JMenuBar
JCheckBoxMenuItem
Para generar el código correspondiente a cada variable de instancia se deberá recorrer
los elementos de la referencia menus de la metaclase MenuManager (que es el contexto
de la regla main). Para cada elemento se llamará a la regla mapInstanceVariable,
que será una regla definida para cada una de las metaclases de la jerarquı́a comentada
anteriormente. El código de cada una de las reglas se debe encargar de definir la variable
de instancia correspondiente al elemento.
Sección 3c. Generación del código para construir los elementos del menú.
Esta sección de código, al igual que en el caso anterior, depende de los elementos de la
referencia menus de la instancia de la metaclase MenuManager. Para cada elemento que se
ha añadido como variable de instancia se debe llamar al constructor. Los constructores
de los anteriores objetos Java son:
8
Metaclase arquitectura
SingleMenuItem
TreeMenu
MenuBar
CheckboxMenuItem
Objeto Java Swing
new JMenuItem(String menuText)
new JMenu(String menuText)
new JMenuBar()
new JCheckBoxMenuItem(String menuText)
Al igual que en el caso anterior, en la regla main se deberá recorrer los elementos de la referencia menus y para cada elemento llamar la regla llamada mapInitializeInstanceVa
riable, que será la encargada de generar el código correspondiente.
Sección 3d. Generar las acciones para los elementos del menú. Esta sección
de código genera un método encargado de asignar las acciones a cada elemento del
menú. Dado que solamente los elementos del menú de tipo SingleMenuItem tendrán
establecida una acción (metaclase Action en el metamodelo de arquitectura), se debe
recorrer la referencia menus para trabajar solamente con elementos de este tipo. Para
cada uno de ellos se añadirá un nuevo listener que apuntará a la clase encargada de
realizar la acción. Dicha clase está especificada en el atributo name de la clase Action
a la que SingleMenuItem hace referencia. Un ejemplo de generación de código para
añadir un listener a un botón serı́a el siguiente:
this.newFile.addActionListener(new centic.listeners.newfileAction());
Sección 3e. Generar los constructores de las barras de menú. Esta sección
de la regla main se encarga de generar el código necesario para incluir un método
cuya finalidad es construir la barra de menú asociada a un perfil. Se generarán tantos
métodos como perfiles tenga la instancia de la metaclase MenuManager. Para ello, se
deberá recorrer la referencia profiles y generar el código necesario para cada entrada.
Los perfiles están compuestos por un conjunto de sentencias que establecen qué menús
debe contener dicho perfil ası́ como sus propiedades básicas. De esta forma, se deberá recorrer la referencia statements para configurar la barra de menú del perfil. Esta
referencia contiene un conjunto de elementos de la jerarquı́a Statement del metamodelo de la arquitectura. Para cada metaclase de la jerarquı́a se creará una regla llamada
mapStatement que se encargará de generar el código asociado al comportamiento de
la sentencia. La siguiente tabla muestra las correspondencias para cada metaclase y la
forma de llevar a cabo el comportamiento en Swing.
Metaclase arquitectura
AddMenu
SetToolTip
DisableMenu
SetShortcut
SetMnemonic
Java Swing
método add(JMenu menu)
método setToolTipText(String text)
método setEnabled(Boolean isEnabled)
método setAccelerator(KeyStroke keyStroke)
método setMnemonic(KeyEvent keyEvent)
Con estas modificaciones, la definición de transformación MOFScript genera el código
necesario para la clase MenuManager. La implementación de dicha transformación se incluye
en el Anexo F.
2.6.1.
Tareas
1. Enriquecer la regla main para que contemple la generación de código para la clase
MenuManager. A ser posible, seguir la nomenclatura mostrada anteriormente.
9
Se debe generar el nombre del paquete.
Generar las variables de instancia para los elementos del menú.
Generar el método encargado de construir los elementos del menú.
Generar el método encargado de establecer las acciones de los elementos del menú.
Generar los constructores para las barras de menú asociadas a cada perfil.
2. Probar la generación de código y comprobar que la clase Application funciona correctamente.
3.
Sesión no guiada
Definir una transformación MOFScript para generar automáticamente los ficheros de
recursos necesarios para la internacionalización. Los ficheros de recursos deberán ser
generados en la carpeta src del proyecto menuprofile.lib.
Modificar la definición de transformación MOFScript para internacionalizarla. Para ello,
deberá utilizar ficheros de recursos para recuperar las cadenas de texto que se muestren
en la aplicación.
10
A.
Resumen sentencias MOFScript
Tipos primitivos. Los tipos primitivos ofrecidos por MOFScript son los siguientes:
String, Integer, Real, Boolean, Hastable, List y Object. El tipo Object permite
representar cualquier tipo.
Trabajo con ficheros. La sentencia file permite establecer el fichero a crear donde
se generará el código indicado en la transformación. El nombre del fichero se indica
como parámetro y puede incluir una ruta relativa o absoluta. Algunos ejemplos de uso
son:
file (" myfile . java ")
file f1 (" myfile2 . java ")
Impresión. Estas sentencias permiten imprimir cadenas de texto en un fichero o en
la pantalla. Las sentencias principales son print y println. Por defecto, se imprime
en el último file indicado pero puede indicarse la salida estándar para imprimir por
pantalla. Algunos ejemplos de uso son:
stdout . println ( ‘ ‘ mensaje ’ ’)
file f1 (" myfile2 . java ")
f1 . print ( ‘ ‘ codigo ’ ’
Iteradores. Los iteradores permiten recorrer colecciones de elementos. La sentencia
forEach define un iterador sobre una colección que puede ser una colección de elementos
del modelo, una lista/hash o una colección de String/Integer. Algunos ejemplos de uso
son:
collection - > forEach ( element )
collection - > forEach ( c : someType )
collection - > forEach ( a : String | a . size () = 2)
Sentencia select. La sentencia select permite realizar una consulta sobre una colección de elementos y devuelve una lista con los elementos encontrados. Actualmente
solamente puede ser utilizada en asignaciones y su sintaxis es muy similar a la utilizada
en la sentencia forEach. Un ejemplo de uso serı́a:
var result : List = self . states - > select ( st : stateMM . State | st . name . startswith ("
,→ ST ") )
Sentencias condicionales. MOFScript ofrece estructuras de tipo if y while. A continuación se muestran ejemplos de cada una de ellas:
if ( c . states > 10) {
// s t a t e m e n t s
} else if ( c . states > 5) {
// s t a t e m e n t s
} else {
// s t a t e m e n t s
}
while ( c . states > 1) {
// s t a t e m e n t s
}
Expresiones lógicas. MOFScript ofrece soporte a expresiones lógicas estándar al igual
que cualquier otro lenguaje de programación.
11
B.
Metamodelo de la arquitectura
MenuManager
profiles *
statements *
ProfileMethod
name : String
root 1
menus *
Statement
child 1
MenuItem
variableId : String
text : String
AddMenu
parent 1
1 menu
MenuStatement
SetStringProperty
Action
name : String
1 action
SingleMenuItem
TreeMenuItem
SetToolTip
CheckboxMenuItem
defaultValue : Boolean
MenuBar
SetMnemonic
SetShortcut
key : String
character : String
DisableMenu
Figura 5: Metamodelo de la arquitectura generada.
12
C.
Código fuente para Application
package centic;
import
import
import
import
import
import
import
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
java.io.IOException;
javax.swing.BoxLayout;
javax.swing.JButton;
javax.swing.JFrame;
javax.swing.JPanel;
public class Application {
public static void main(String[] args) throws IOException {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
ApplicationExample theInstance = new ApplicationExample();
((ApplicationExample) theInstance).createAndShowGUI();
}
});
}
public void createAndShowGUI() {
// Create and set up the window.
final JFrame frame = new JFrame("Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPane = new JPanel();
BoxLayout layout = new BoxLayout(mainPane, BoxLayout.Y_AXIS);
mainPane.setLayout(layout);
frame.setContentPane(mainPane);
JButton ProfileAButton = new JButton("ProfileA");
ProfileAButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setJMenuBar(MenuManagerExample.INSTANCE.getProfileProfileA() );
frame.pack();
}
});
mainPane.add(ProfileAButton);
JButton ProfileBButton = new JButton("ProfileB");
ProfileBButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setJMenuBar(MenuManagerExample.INSTANCE.getProfileProfileB() );
frame.pack();
}
});
mainPane.add(ProfileBButton);
// Show the window.
frame.pack();
frame.setVisible(true);
}
}
13
D.
Código fuente para la clase MenuManager
package centic;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
class MenuManager {
private JMenu file;
private JMenuItem newFile;
private JMenuItem close;
private JMenuItem exit;
private JMenuBar profileAProfileMenu;
private JMenuBar profileBProfileMenu;
public final static MenuManager INSTANCE = new MenuManager();
private MenuManager() {
createSingleMenus();
attachListeners();
}
public void createSingleMenus() {
this.file = new JMenu("File");
this.newFile = new JMenuItem("New File");
this.close = new JMenuItem("Close");
this.exit = new JMenuItem("Exit");
this.profileAProfileMenu = new JMenuBar();
this.profileBProfileMenu = new JMenuBar();
}
public void attachListeners() {
this.newFile.addActionListener(new centic.listeners.newfileAction());
this.close.addActionListener(new centic.listeners.closeAction());
this.exit.addActionListener(new centic.listeners.exitAction());
}
public JMenuBar getProfileProfileA() {
this.profileAProfileMenu.add(this.file);
this.file.add(this.exit);
this.exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, ActionEvent.CTRL_MASK));
this.exit.setMnemonic(KeyEvent.VK_S);
return profileAProfileMenu;
}
public JMenuBar getProfileProfileB() {
this.profileBProfileMenu.add(this.file);
this.file.add(this.newFile);
this.file.add(this.close);
this.file.add(this.exit);
return profileBProfileMenu;
}
}
14
E.
Definición de transformación MOFScript para la clase Application
menu . MenuManager :: main () {
file ( pkgDir + ’ Application . java ’ )
’ package ’ package ’;
import java . awt . event . ActionEvent ;
import java . awt . event . Act ionListe ner ;
import java . io . IOException ;
import
import
import
import
javax . swing . BoxLayout ;
javax . swing . JButton ;
javax . swing . JFrame ;
javax . swing . JPanel ;
public class Application {
public static void main ( String [] args ) throws IOException {
javax . swing . Swi ngUtilit ies . invokeLater ( new Runnable () {
public void run () {
Application theInstance = new Application () ;
(( Application ) theInstance ) . c r e a t e A n d S h o w G U I () ;
}
}) ;
}
public void c r e a t e A n d S h o w G U I () {
// Create and set up the window .
final JFrame frame = new JFrame (" Application ") ;
frame . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT_ON_CLOSE ) ;
JPanel mainPane = new JPanel () ;
BoxLayout layout = new BoxLayout ( mainPane , BoxLayout . Y_AXIS ) ;
mainPane . setLayout ( layout ) ;
frame . setCo ntentPan e ( mainPane ) ;
’
’
’
self . profiles - > forEach ( c : menu . ProfileMethod ) {
JButton ’ c . name ’ Button = new JButton (" ’ c . name ’ ") ;
’c . name ’ Button . a d d A c t i o n L i s t e n e r ( new Acti onListe ner () {
public void ac ti o nP er fo r me d ( ActionEvent e ) {
frame . setJMenuBar ( MenuManager . INSTANCE . ’ c . p r o f i l e M e t h o d N a m e ()
,→ ’ () ) ;
frame . pack () ;
}
}) ;
mainPane . add ( ’ c . name ’ Button ) ; ’ newline (1)
}
// Show the window .
frame . pack () ;
frame . setVisible ( true ) ;
}
}
’
}
menu . ProfileMethod :: p r o f i l e M e t h o d N a m e () : String {
result = ’ getProfile ’ + self . name ;
}
15
F.
Definición MOFScript para generar la clase MenuManager
// ( c o n t i n u a la d e f i n i c i n de la regla main )
file ( pkgDir + ’ MenuManager . java ’ )
’ package ’ package ’;
import java . awt . event . ActionEvent ;
import java . awt . event . KeyEvent ;
import
import
import
import
import
javax . swing . J C h e c k B o x M e n u I t e m ;
javax . swing . JMenu ;
javax . swing . JMenuBar ;
javax . swing . JMenuItem ;
javax . swing . KeyStroke ;
class MenuManager { ’ newline (1)
self . menus - > forEach ( m : menu . MenuItem ) {
m . m a p I n s t a n c e V a r i a b l e ()
}
’
public final static MenuManager INSTANCE = new MenuManager () ;
private MenuManager () {
c r e a t e S i n g l e M e n u s () ;
a tt ac h Li st en e rs () ;
}
public void c r e a t e S i n g l e M e n u s () { ’ newline (1)
self . menus - > forEach ( m : menu . MenuItem ) {
m . m a p I n i t i a l i z e I n s t a n c e V a r i a b l e () ;
}
’
} ’ newline (2)
’
public void at t ac hL is t en er s () { ’ newline (1)
self . menus - > forEach ( m : menu . Sing leMenuIt em ) {
this . ’ m . variableId ’. a d d A c t i o n L i s t e n e r ( new ’ li s te ne rP a ck ag e ’. ’ m .
,→ action . name ’ () ) ; ’ newline (1)
}
} ’ newline (2)
’
’
self . profiles - > forEach ( p : menu . ProfileMethod ) {
public JMenuBar ’ p . p r o f i l e M e t h o d N a m e () ’ () { ’ newline (1)
p . statements - > forEach ( s ) {
s . mapStatement ()
}
return ’ p . root . variableId ’;
} ’ newline (2)
}
’
’
’} ’
}
// C r e a t i n g i n s t a n c e v a r i a b l e s
abstract menu . MenuItem :: m a p I n s t a n c e V a r i a b l e () ;
menu . Si ngleMenu Item :: m a p I n s t a n c e V a r i a b l e () {
’
private JMenuItem ’ self . variableId ’; ’ newline (1)
}
menu . TreeMenuItem :: m a p I n s t a n c e V a r i a b l e () {
’
private JMenu ’ self . variableId ’; ’ newline (1)
}
menu . MenuBar :: m a p I n s t a n c e V a r i a b l e () {
’
private JMenuBar ’ self . variableId ’; ’ newline (1)
}
16
menu . C h e c k b o x M e n u I t e m :: m a p I n s t a n c e V a r i a b l e () {
’
private J C h e c k B o x M e n u I t e m ’ self . variableId ’; ’ newline (1)
}
// I n i t i a l i z i n g i n s t a n c e v a r i a b l e s
menu . Si ngleMenu Item :: m a p I n i t i a l i z e I n s t a n c e V a r i a b l e () {
’
this . ’ self . variableId ’ = new JMenuItem ( I n t e r n a t i o n a l i z a t i o n .
,→ getInstance () . getString (" ’ self . variableId ’ ") ) ; ’ newline (1)
}
menu . TreeMenuItem :: m a p I n i t i a l i z e I n s t a n c e V a r i a b l e () {
’
this . ’ self . variableId ’ = new JMenu ( I n t e r n a t i o n a l i z a t i o n .
,→ getInstance () . getString (" ’ self . variableId ’ ") ) ; ’ newline (1)
}
menu . MenuBar :: m a p I n i t i a l i z e I n s t a n c e V a r i a b l e () {
’
this . ’ self . variableId ’ = new JMenuBar () ; ’ newline (1)
}
menu . C h e c k b o x M e n u I t e m :: m a p I n i t i a l i z e I n s t a n c e V a r i a b l e () {
’
this . ’ self . variableId ’ = new J C h e c k B o x M e n u I t e m (
,→ I n t e r n a t i o n a l i z a t i o n . getInstance () . getString (" ’ self . variableId ’ ") ) ; ’
,→ newline (1)
if ( self . defaultValue = true ) {
’
this . ’ self . variableId ’. setSelected ( true ) ; ’ newline (1)
}
}
// M a p p i n g s s t a t e m e n t s
menu . AddMenu :: mapStatement () {
’
this . ’ + self . parent . variableId ’. add ( this . ’ self . child . variableId ’) ;
,→ ’ newline (1)
}
’
’
menu . SetToolTip :: mapStatement () {
this . ’ + self . menu . variableId ’. setT oolTipTe xt (" ’ self . value ’ ") ; ’
,→ newline (1)
}
menu . DisableMenu :: mapStatement () {
this . ’ self . menu . variableId ’. setEnabled ( false ) ; ’ newline (1)
}
menu . SetShortcut :: mapStatement () {
if ( not self . menu . oclIsKindOf ( menu . TreeMenuItem ) ) {
’
this . ’ + self . menu . variableId ’. setA ccelerat or ( KeyStroke . getKeyStroke (
,→ KeyEvent . VK_ ’ self . character ’ , ActionEvent . ’ self . key ’ _MASK ) ) ; ’ newline (1)
}
}
’
menu . SetMnemonic :: mapStatement () {
this . ’ + self . menu . variableId ’. setMnemonic ( KeyEvent . VK_ ’ self . value .
,→ toUpper () ’) ; ’ newline (1)
}
17