Desarrollo de DSL visuales con Graphiti

Tutorial

Instalación de Graphiti.

Para trabajar con este plugin hemos utilizado la versión Kepler de Eclipse Modelling Tools.

He hecho uso de esta versión de Eclipse ya que la versión Luna de Eclipse me daba problemas con el plugin Spray que también veremos en tecnologías relacionadas. El problema que me daba era que el Proyecto de Spray no me dejaba crearlo.

Una vez que tenemos Eclipse en funcionamiento, seguimos los siguientes pasos:

  1. Seleccionamos Help > Intall New Software.

  2. Añadimos el enlace que encontramos en la página de Eclipse para instalar Graphiti, en este caso la versión 10.02.

  3. Seleccionamos el checkbox Graphiti > seleccionamos Next como aparece en la imagen anterior.

  4. Aceptamos la licencia y seleccionamos Finish. Una vez terminado nos pedirá que reiniciemos Eclipse y tras esto ya estaremos listos para utilizar el plugin de Graphiti.

Caso de estudio: Desarrollo de un DSL con Graphiti.

Para este caso de estudio de este plugin de Eclipse, vamos a crear un mini DSL de una Biblioteca. Para esto seguiremos los siguientes pasos:

  1. Creamos un nuevo proyecto EMF (File > New > Other > Eclipse Modelling Framework > Empty Empty Project) con el nombre org.eclipse.graphiti.ej.

  2. Ahora creamos un modelo Ecore (Botón derecho en el Directorio Model > New > Other > Eclipse Modelling Framework) con el ej.ecore.

  3. Abrimos el fichero ecore y seleccionamos el item , abrimos la vista de Propiedades y agregamos las propiedades Ns, Ns Prefix, Ns URI. Y antes de seguir para evitar problemas futuros validamos el fichero haciendo click derecho sobre el '.Ecore' y seleccionamos Validar.

  4. Volvemos a hacer click derecho sobre el fichero '.ecore' > Initialize Ecore Diagram File > Finish. Este paso nos creara un nuevo archivo '.ecorediag' donde tendremos un editor gráfico que nos permitirá escribir nuestro modelo que serán el siguiente:

  5. Volvemos a validar el modelo como hicimos anteriormente a través del modelo Ecore. Una vez que el modelo sea correcto, generamos el código el código de nuestro DSL. Primero le decimos que nos construya el Path para el el directorio src que va a contener el código de nuestro modelo. (Click derecho en el directorio Model > Build Path > Use as a source Folder).

  6. Click derecho sobre el proyecto org.eclipse.graphiti.ej > Configure > Add Xtext Nature > Refrescamos con F5 el proyecto para generar el código estandar de nuestro proyecto.

  7. A continuación vamos a generar el fichero '.genmodel' para esto seleccionamos el fichero '.ecore' del directorio Model > Botón derecho > New > Other > Eclipse Modeling Project > Emf Generator Model. Nos saldrá un cuadro de dialogo para crear el GenModel, le damos a Next > Select Ecore Model(CDO Native) as Model Importers > Next > Finish.

  8. Una vez creado seleccionamos el fichero '.genmodel' lo abrimos y seleccionamos el elemento Tutorial_iia al desplegar el primer elemento del fichero > Click derecho > Seleccionamos Generate Model Code. En este paso obtendremos dentro de la carpeta src los paquetes java: Tutorial_iia, Tutorial_iia.util y Tutorial_iia.impl con todas las clases Java necesarias para nuestro DSL.

  9. Ahora mismo ya tenemos el código de nuestro DSL, solo tendremos que configurar nuestro editor haciendo uso de la API de Java que nos pone a disposición Graphiti. Para esto primero vamos a configurar el Plugin.xml del proyecto, abrimos el fichero por la prespectiva Extensions y a la izquierda tendremos todas las extensiones. En primero lugar nos encontraremos: org.eclipse.emf.ecore.generate_packages.

  10. Añadimos los plugins siguiente con sus respectivas propiedades:

    1. org.eclipse.graphiti.ui.diagramTypes.
      • id: bibliotecademo.BibliotecaDiagramType
      • type: BibliotecaDemo
      • name: Diagram Types for Biblioteca Demo
    2. org.eclipse.graphiti.ui.diagramTypeProvider.
      • id: bibliotecademo.BibliotecaDiagramTypeProvider
      • type: Biblioteca Demo Editor
      • class: tutorial_iia.BibliotecaDiagramTypeProvider Lo más importante es colocar bien la clase de BibliotecaDiagramTypeProvider que vamos a generar para configurar nuestro editor dentro del paquete Java demobiblioteca.
  11. Además copiamos el fichero bibliotecademo.BibliotecaDiagramType dentro del fichero bibliotecademo.BibliotecaDiagramTypeProvider y que tendrá el id: bibliotecademo.BibliotecaDiagramType. Al final tendria que quedarnos algo así.

  12. Luego nos vamos en el mismo fichero de plugin.xml a la perspectiva Dependencies y añadimos las Dependencias que vamos a necesitar o directamente las escribimos en la perspectiva MANIFEST.MF. Para el caso de org.eclipse.graphiti.mm tendremos que añadirlo a mano ya que la que se encuentra en dependencias para añadir por defecto es org.eclipse.graphiti.mm.source.

    Require-Bundle: org.eclipse.core.runtime,
    org.eclipse.emf.ecore;visibility:=reexport,
    org.eclipse.graphiti.ui,
    org.eclipse.emf.cdo;visibility:=reexport,
    org.eclipse.graphiti;bundle-version="0.10.2",
    org.eclipse.graphiti.mm;bundle-version="0.10.2",
    org.eclipse.emf.transaction;bundle-version="1.4.0"
    
  13. Configuramos las propiedades de nuestro editor picando código en Java haciendo uso de la API de Graphiti. Los ficheros se encuentran dentro del directorio src/bibliotecademo. Dscribiremos su estructura al final de este tutorial.

  1. Una vez programado solo tendremos que hacer click derecho sobre el proyecto > Run As > Eclipse Aplication y comenzara a correr otro Eclipse.

  2. Una vez abierto el segundo Eclipse haciendo click en File > New > Example > Graphiti Sample Project > Next > Ponemos un nombre del Proyecto Graphiti > Finish. Tras este paso seleccionamos el proyecto en la perspectiva Package Explorer de Eclipse y hacemos New > Example > Graphiti Diagram > Next > Seleccionamos nuestro Diagram Type (BibliotecaDemo) > Ponemos un nombre al diagrama > Finish.

  3. Una vez llegados a este punto ya tendremos nuestro editor de DSL para generarlos a través del diagrama con Graphiti. El resultado sería este.

Aquí explicaremos alguno ejemplos de ficheros que hemos tenido que implementar en el punto 13 para configurar nuestro editor.

BibliotecaDiagramTypeProvider.java

Este clase de Java nos va a permitir crear la clase diagrama para nuestro propio editor y va a llamar a la clase BibliotecaDiagramFeature que se va a encargar de llamar a cada una de las clases de los elementos de la paleta de herramientas para dibujarlo en el diagrama.

package bibliotecademo;
import org.eclipse.graphiti.dt.AbstractDiagramTypeProvider;

public class BibliotecaDiagramTypeProvider extends AbstractDiagramTypeProvider {

        public BibliotecaDiagramTypeProvider() {
            super();
            setFeatureProvider(new BibliotecaDiagramFeatureProvider(this));
        }
}

BibliotecaDiagramFeatureProvider.java

Esta clase nos va a llamar a cada una de los elementos del diagrama y va a añadirlo al Diagrama que ve el usuario.

package bibliotecademo;
import tutorial_iia.*;

import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.ICreateConnectionFeature;
import org.eclipse.graphiti.ui.features.DefaultFeatureProvider;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.ICreateFeature;
import org.eclipse.graphiti.features.context.IAddContext;

public class BibliotecaDiagramFeatureProvider extends DefaultFeatureProvider {

    public BibliotecaDiagramFeatureProvider(IDiagramTypeProvider dtp) {
        super(dtp);
    }

    @Override
    public ICreateFeature[] getCreateFeatures() {
        return new ICreateFeature[] { new CreateLibroDiagram(this), new CreateUsuarioDiagram(this),  new CreateBibliotecaDiagram(this)};
    }

    @Override
    public ICreateConnectionFeature[] getCreateConnectionFeatures() {
        return new ICreateConnectionFeature[] { new CreateConnectionDiagram(this)};
    }

    @Override
    public IAddFeature getAddFeature(IAddContext context) {
        if(context.getNewObject() instanceof Libro) {
            return new AddLibroFeature(this);
        }
        if (context.getNewObject() instanceof Usuario) {
            return new AddUsuarioFeature(this);
        }
        if (context.getNewObject() instanceof Biblioteca) {
            return new AddBibliotecaFeature(this);
        }
        return super.getAddFeature(context);
    }
}

Ahora veremos un ejemplo de como se programa un elemento del diagrama, para meterlo en la paleta de herramientas , para esto utilizaremos los siguientes ficheros:

CreateBibliotecaDiagram.java

En esta clase lo que haremos será crear el objeto Biblioteca y añadir la representación gráfica del objeto que se implemente en la clase AddBibliotecaFeature. java.

package bibliotecademo;

import org.eclipse.graphiti.features.ICreateFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.ICreateContext;
import org.eclipse.graphiti.features.impl.AbstractCreateFeature;
import org.eclipse.graphiti.mm.pictograms.Diagram;

import tutorial_iia.Biblioteca;
import tutorial_iia.Libro;
import tutorial_iia.Tutorial_iiaFactory;

public class CreateBibliotecaDiagram extends AbstractCreateFeature implements ICreateFeature{

        public CreateBibliotecaDiagram(IFeatureProvider P){
            super(P,"Biblioteca","Biblioteca");
        }

        @Override
        public boolean canCreate(ICreateContext context) {
            return context.getTargetContainer() instanceof Diagram;
        }

        @Override
        public Object[] create(ICreateContext context) {
            Biblioteca p= Tutorial_iiaFactory.eINSTANCE.createBiblioteca();
            context.getTargetContainer().eResource().getContents().add(p);
            addGraphicalRepresentation(context, p);
            return new Object[] {p};
        }

}

AddBibliotecaFeature.java

En esta clase se define la representación gráfica del objeto Biblioteca que va a crear la clase anterior.

package bibliotecademo;

import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.impl.AbstractAddShapeFeature;
import org.eclipse.graphiti.mm.algorithms.Rectangle;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.services.IGaService;
import org.eclipse.graphiti.services.IPeService;
import org.eclipse.graphiti.util.IColorConstant;

import tutorial_iia.Biblioteca;
import tutorial_iia.Libro;


public class AddBibliotecaFeature extends AbstractAddShapeFeature implements IAddFeature {

    private static final int SQUARE_SIZE = 30;
    private static final int BOARD_SIZE = SQUARE_SIZE * 5;

    public AddBibliotecaFeature(IFeatureProvider fp) {
        super(fp);
    }

    @Override
    public boolean canAdd(IAddContext context) {
        return context.getNewObject() instanceof Biblioteca && context.getTargetContainer() instanceof Diagram;
    }

    @Override
    public PictogramElement add(IAddContext context) {

        // Get Graphiti services for easier access
        IPeService peService = Graphiti.getPeService();
        IGaService gaService = Graphiti.getGaService();
        Biblioteca biblioteca = (Biblioteca) context.getNewObject();

        // Create the visualisation of the board as a square
        ContainerShape bookShape = peService.createContainerShape(getDiagram(), true);
        Rectangle bookRectangle = gaService.createRectangle(bookShape);
        gaService.setLocationAndSize(bookRectangle, context.getX(), context.getY(), 20, 95);

        IColorConstant color;
        color = IColorConstant.GREEN;
        bookRectangle.setBackground(manageColor(color));
        // Link the visualisation with the board
        link(bookShape, biblioteca);


        return bookShape;
    }
}

Ficheros empleados.

La estructura del proyecto necesario para generar nuestro propio DSL es el que se ve en la imagen:

La estructura del proyecto de Graphiti puede verse en la siguiente imagen:

En la carpeta src, irá todo el código generado (tutorial_iia, tutorial_iia.impl, tutotial_iaa.util) y el código que nosotros utilicemos para generar las features de nuestros nuevos diagramas (bibliotecademo). Y en la carpeta model, irán todos los modelos que necesitamos (.ecore, ecorediag y genmodel).

Ejemplos disponibles.

Graphiti ya dispone de diagramas de ejemplos, los disponibles son los siguientes:

Tutorial

Es un editor que nos permite crear diagramas de clases simples como puede verse en la imagen. En la paleta de herramientas por tanto cuenta con el tipo Clase (EClass) y la unión entre clases (EReference).

Filesystem

Este editor nos permite crear un sistema de ficheros, por lo tanto cuenta como herramientas: el sistema de ficheros que va a contener toda nuestra información, el fichero (File) como unidad simple y la carpeta o directorio (Folder) donde podemos almacenar más ficheros. Además cuenta con un elemento contenedor (Containment) que será la relación que indica que elemento contiene a cada uno.

Chess

Este último ejemplo, es un editor para construir un ajedrez. El editor nos permite dibujar el Tablero del Juego (Create Board), crear las piezas en el tablero (Create Pieces) e incluso dibujar los movimientos de cada pieza (Create Move).