Sesión 4 Generación de código (MOFScript) Proyecto AutoGSA Sesión 4 Generación de código (MOFScript)
Desarrollo de la sesión Generación de código MOFScript Ejemplo Generar el código DOT para una máquina de estados Pasos Definir el metamodelo origen Definir la transformación MOFScript Ejecutar / Corregir la transformación Presentación del entorno Desarrollo del guión
Generación de código Última fase del proceso DSDM Lenguajes de transformación modelo a código MOFScript, Xpand, JET, Velocity, XSLT,… MOF2Text M2C Modelos Código M2M
Lenguaje de plantillas Permite expresar plantillas El texto de salida con los “huecos” en los que se debe insertar las partes variables En los “huecos” se escribe el código que accede al modelo y calcula las partes variables. Mecanismos básicos Primitivas de acceso a los elementos del modelo origen Iteradores para recorrer los elementos del modelo Invocación de plantillas
Lenguaje de plantillas. Ejemplo JButton NoviceButton = new JButton("Novice"); NoviceButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setJMenuBar(MenuManager.INSTANCE.getProfileNovice() ); frame.pack(); } }); mainPane.add(NoviceButton); JButton AdvancedButton = new JButton("Advanced"); AdvancedButton.addActionListener(new ActionListener() { frame.setJMenuBar(MenuManager.INSTANCE.getProfileAdvanced() ); mainPane.add(AdvancedButton); frame.setVisible(true);
Lenguaje de plantillas. Ejemplo JButton NoviceButton = new JButton("Novice"); NoviceButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setJMenuBar(MenuManager.INSTANCE.getProfileNovice() ); frame.pack(); } }); mainPane.add(NoviceButton); JButton AdvancedButton = new JButton("Advanced"); AdvancedButton.addActionListener(new ActionListener() { frame.setJMenuBar(MenuManager.INSTANCE.getProfileAdvanced() ); mainPane.add(AdvancedButton); frame.setVisible(true);
Lenguaje de plantillas. Ejemplo Repetir tantas veces como botones queramos añadir { JButton Button = new JButton(" "); NoviceButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setJMenuBar(MenuManager.INSTANCE.get () ); frame.pack(); } }); mainPane.add( Button); frame.setVisible(true);
Lenguaje de plantillas. Ejemplo MOFScript Window.buttons->forEach(b : Button) { ' JButton ' b.varName 'Button = new JButton("' b.text '"); NoviceButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setJMenuBar(MenuManager.INSTANCE.get' b.callMethod '() ); frame.pack(); } }); mainPane.add(' b.varName ' Button); ' frame.setVisible(true);
Generación de código El concepto de lenguaje de plantillas conforma Motor de plantillas Plantilla Modelo Código conforma Metamodelo
Desarrollo de la sesión Generación de código MOFScript Ejemplo Generar el código DOT para una máquina de estados Pasos Definir el metamodelo origen Definir la transformación MOFScript Ejecutar / Corregir la transformación Presentación del entorno Desarrollo del guión
MOFScript Lenguaje M2C basado en reglas Transformaciones organizadas en módulos Un módulo está compuesto por reglas Un módulo puede extender a otro módulo (herencia / importación) texttransformation myDef (in metamodel:"http://modelum.es/mm") { metamodel.Metaclass::main() { 'The name of this metaclass is ' self.name ' here you can add your code' } module::myRule1(name : String) { tab(1) 'This is a rule with a parameter, its value is ' name newline(1) myRule2() : String { tab(1) 'This rule returns a value' newline(1) result = 'name'
MOFScript Formas de generar código Uso del carácter de escape (text-explicit) Útil cuando se va a generar gran cantidad de código sin cambios Uso de sentencias de generación de código (code-explicit) Útil cuando el código a generar es pequeño o muy parametrizado module::myRule1(name : String) { ' This is a rule with a parameter, its value is ' name ' ' } module::myRule1(name : String) { tab(1) print("This is a rule with a parameter, its value is" + name) newline(1) } module::myRule1(name : String) { tab(1) 'This is a rule with a parameter, its value is' name newline(1) }
MOFScript Contexto, argumentos y devolución de valores en las reglas Reglas entry-point (main) texttransformation myDef (in metamodel:"http://modelum.es/mm") { metamodel.Metaclass::main() { 'The name of this metaclass is ' self.name ' here you can add your code' } module::myRule1(name : String) { tab(1) 'This is a rule with a parameter, its value is ' name newline(1) myRule2() : String { tab(1) 'This rule returns a value' newline(1) result = 'name'
MOFScript Polimorfismo y ligadura dinámica Reglas con el mismo identificador para diferentes contextos Resolución de reglas en tiempo de ejecución metamodel.MetaclassA::rule() { 'Code for MetaclassA' } metamodel.MetaclassB::rule() { 'Code for MetaclassB' metamodel.MetaclassC::rule() { 'Code for MetaclassC' SuperMetaclass MetaclassA MetaclassC MetaclassB metamodel.Metaclass::main() { self.content->forEach(s) { s.rule(); } content Metaclass SuperMetaclass
MOFScript Acceso al modelo desde las reglas Machine::rule1() { var name : String = self.name var transitions : List = self.transitions } Transition::rule2() { var target : State = self.target var transitions : List = target.outgoing 29/03/2017
MOFScript Iteradores para recorrer los elementos del modelo Sentencia forEach Sentencia select var complexStates : List self.states->forEach(st : State | st.outgoing.size > 2) { complexStates.add(st) } var complexStates : List = self.states->select(st : State | st.outgoing.size > 2) complextates->forEach(st) { . . . } 29/03/2017
MOFScript Sentencias útiles Para colecciones de elementos size() : Devuelve el número de elementos de la colección add(e : Object) : Añade un elemento de la colección remove(e : Object) : elimina un elemento de la colección Para cadenas de texto replace(replaceWhat : String, withWhat : String) equals(str: String) toLower() toUpper() Gestión de ficheros file(str : String) Impresión print(str : String) println(str : String) stdout: Descriptor de la salida estándar (stdout.println()) 29/03/2017
Desarrollo de la sesión Generación de código MOFScript Ejemplo Generar el código DOT para una máquina de estados Pasos Definir el metamodelo origen Definir la transformación MOFScript Ejecutar / Corregir la transformación Presentación del entorno Desarrollo del guión
Definir el metamodelo origen Metamodelo de máquinas de estados
Lenguaje DOT Es un lenguaje para la definición de grafos Permite generar la representación gráfica de un grafo Formato JPG, PS, PDF, etc. Una definición DOT está compuesta por: Tipo de grafo Definición de arcos entre dos nodos Tipo de nodo o de arco (opcional) digraph ej1 { a -> b; a -> c; c -> d; b -> d; }
Lenguaje DOT Personalizando DOT para representar máquinas de estados digraph Modernization { Start -> ExtractingModels; ExtractingModels -> MDD [label="C2M"]; MDD -> MDD [label="M2M"]; MDD -> SystemGeneration [label="M2C"]; SystemGeneration -> End; Start [shape=point,width=0.2,label=""]; ExtractingModels [label="Extracting Models",shape=ellipse]; MDD [shape=ellipse]; SystemGeneration [label="System Generation",shape=ellipse]; End [shape=doublecircle,label="",width=0.2, fillcolor=black,style=filled]; }
Correspondencias metamodelo – DOT Machine Esqueleto de la definición DOT digraph Nombre { // contenido…} Transition Definición de arco DOT N1 -> N2 [label=“etiqueta”] InitialState Definición de nodo DOT personalizado Start[shape=point,width=0.2,label=""]; NormalState Normal_State[label="Normal State",shape=ellipse]; EndState End[shape=doublecircle,label="",width=0.2, fillcolor=black,style=filled];
Definir la transformación MOFScript Un grafo para cada máquina de estados El esqueleto de la definición DOT se creará para cada metaclase Machine. Una regla para generar el código de las transiciones Indicará el estado origen y el estado destino Una regla para generar el código de los estados Personalizará la representación de cada estado Especificar reglas para los tres tipos de estados texttransformation StateMachine2DotTransformation (in stateMM:"http://www.modelum.es/dsdm/stateMachine") { // Reglas… }
Definir la transformación MOFScript Creación de una regla main. Uso del carácter de escape Uso de iteradores para recorrer estados y transiciones Ejemplo de código DOT a generar: digraph Nombre { // contenido… } Regla MOFScript: stateMM.Machine::main() { file(outputFile) 'digraph ' self.name ' { // Transitions // There are ' self.transitions.size() ' transitions ' self.transitions->forEach(t) { t.mapTransition() } ' // States // There are ' self.states.size() ' states ' self.states->forEach(st) { st.mapState(); } ' }' }
Definir la transformación MOFScript Reglas para la creación del código de las transiciones Ejemplo de código DOT a generar : N1 -> N2 [label=“etiqueta”] Regla MOFScript: Reglas para la creación del código de los nodos Estado inicial Start[shape=point,width=0.2,label=""]; stateMM.Transition::mapTransition() { tab(1) self.source.getName() ' -> ' self.target.getName() ' [label="' self.name '"];' newline(1) } stateMM.InitialState::mapState() { tab(1) self.getName() '[shape=point,width=0.2,label=""];' newline(1) }
Definir la transformación MOFScript Estado Final Ejemplo de código DOT a generar: End[shape=doublecircle,label="",width=0.2,fillcolor=black, style=filled]; Regla MOFScript: Estado normal Normal_State[label="Normal State",shape=ellipse]; stateMM.FinalState::mapState() { tab(1) self.getName() '[shape=doublecircle,label="",' 'width=0.2,fillcolor=black,style=filled];' newline(1) } stateMM.NormalState::mapState() { tab(1) self.getName() '[label="' self.name '",shape=ellipse];' newline(1) }
Definir la transformación MOFScript Reglas auxiliares para los nombres de los estados stateMM.InitialState::getName() : String { result = 'Start' } stateMM.FinalState::getName() : String { result = 'End' stateMM.NormalState::getName() : String { result = self.name.replace(" ", "_")
Ejecución de la transformación digraph Modernization { // Transitions // There are 5 transitions in the state machine Start -> Extracting_Models [label=""]; Extracting_Models -> MDD [label="C2M"]; MDD -> MDD [label="M2M"]; MDD -> System_Generation [label="M2C"]; System_Generation -> End [label=""]; // States // There are 5 states in the state machine Start[shape=point,width=0.2,label=""]; Extracting_Models[label="Extracting Models",shape=ellipse]; MDD[label="MDD",shape=ellipse]; System_Generation[label="System Generation",shape=ellipse]; End[shape=doublecircle,pheripheries=2,label="",width=0.2, fillcolor=black,style=filled]; } Código DOT Motor MOFScript Definición MOFScript
Desarrollo de la sesión Generación de código MOFScript Ejemplo Generar el código DOT para una máquina de estados Pasos Definir el metamodelo origen Definir la transformación MOFScript Ejecutar / Corregir la transformación Presentación del entorno Desarrollo del guión
Presentación del entorno El plugin para eclipse se puede descargar de http://www.eclipse.org/gmt/mofscript/download/
Presentación del entorno Hoja de preferencias
Presentación del entorno Preferencias individuales de cada fichero MOFScript
Desarrollo de la sesión Generación de código MOFScript Ejemplo Generar el código DOT para una máquina de estados Pasos Definir el metamodelo origen Definir la transformación MOFScript Ejecutar / Corregir la transformación Presentación del entorno Desarrollo del guión
Sesión guiada Metamodelo de arquitectura
Sesión guiada Arquitectura Java Swing // 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 inclusion de barra de menu JFrame app = new JFrame("App"); app.setJMenuBar(menuBar);
Sesión guiada Generación del código para una aplicación Java Swing Incorporación de una barra de menú dependiente del perfil Generación de dos clases Java Application: Mostrará la ventana y botones para cambiar de perfil MenuManager: Creará los menús asociados a cada perfil
Sesión guiada Clase Application JButton ProfileAButton = new JButton("ProfileA"); NoviceButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setJMenuBar(MenuManager.INSTANCE.getProfileProfileA() ); frame.pack(); } }); mainPane.add(ProfileAButton); 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); mainPane.add(AdvancedButton); // Show the window. frame.pack(); frame.setVisible(true);
Sesión guiada Clase MenuManager // Seccion 1. Definición de paquete // Seccion 2. Imports class MenuManager { // Sección 3a. Variables de instancia (elementos del menú) public final static MenuManager INSTANCE = new MenuManager(); // Sección 3b. Constructor private MenuManager() { createSingleMenus(); attachListeners(); } public void createSingleMenus() { // Sección 3c. Construcción de las variables de instancia public void attachListeners() { // Sección 3d. Establecimiento de las acciones de menu // Sección 3e. Constructores de la barra de menú de cada perfil
Sesión no guiada Generar los ficheros de recursos para la internacionalización Modificar la definición MOFScript para internacionalizarla Uso del proyecto menuprofile.lib Utilizar la clase singleton llamada Internacionalization Método getMessage(String key) file=File new=New close=Close file=Archivo new=Nuevo close=Cerrar menu_es_ES.properties menu_en_US.properties