Detalles de una transformación de modelo a modelo con un proyecto como origen

Es posible modificar el código fuente generado de una transformación de modelo a modelo de forma que se pueda especificar un proyecto que contenga diversos modelos como origen de la transformación.
Normalmente el usuario de una transformación especifica un modelo como origen de la transformación de modelo a modelo, porque, de forma predeterminada, una transformación de este tipo admite un modelo como entrada. En este ejemplo se muestra cómo personalizar el código de la transformación generada, de forma que los usuarios puedan definir como origen un proyecto de Eclipse en vez de un archivo de modelo, y el código personalizado determina qué modelos del proyecto se van a transformar. Los modelos UML con una extensión .emx del proyecto designado se recopilan durante la ejecución de la transformación, en vez de hacerlo cuando se configura el proceso, y se utilizan como entrada de la transformación.
Nota: En este ejemplo, el orden en el que la transformación procesa los modelos de origen no es importante. Para procesar los modelos en un orden determinado, añada el código correspondiente a la implementación de la clase llamada ProjectContentsExtractor.

Este ejemplo contiene un modelo de correlación de transformación que define las correlaciones básicas para los modelos, paquetes y clases UML. La transformación generada crea un modelo UML que tiene el mismo nombre que el proyecto de origen y, en ese modelo, se crea un paquete para cada modelo UML que contenga el proyecto de origen. En cada clase del modelo UML de origen correspondiente, la transformación también crea una clase para cada paquete. Aunque el modelo de correlación es sencillo, la transformación generada muestra cómo se debe personalizar el código para que admita la definición de modelos de origen si se especifica un proyecto de origen.

En este ejemplo se muestra cómo personalizar los elementos siguientes en la transformación generada:
  • El punto de ampliación de la transformación en el archivo plugin.xml generado
  • El método isSourceElementValid en el validador de la transformación generada
  • El método createRootTransformation en el proveedor de la transformación generada

Personalización del archivo plugin.xml generado

En el archivo plugin.xml, en el punto de ampliación de la transformación, la propiedad llamada sourceModelType define el tipo de objetos que el usuario de la transformación puede especificar como origen de la conversión. Cuando se crea un proyecto de transformación de modelo a modelo, de forma predeterminada, el valor de esta propiedad es resource, que significa que el usuario debe especificar un archivo existente en el área de trabajo como origen de la transformación, dentro del asistente y del editor de configuración de transformación. Cuando se establece el valor de la propiedad sourceModelType en project, el usuario de la transformación podrá especificar un proyecto de Eclipse, en vez de un archivo, como origen de la transformación.

Personalización de la clase de validador de la transformación

El asistente y editor de configuración de transformación utiliza la clase de validador para comprobar que la transformación puede ejecutarse correctamente con los valores que ha especificado el usuario. En la clase de validador de transformación, la implementación predeterminada del método llamado isSourceElementValid devuelve true sólo si el origen especificado de la transformación es un archivo.

En este ejemplo, la clase de validador llamada Project4sourceTransformationValidator verifica que la transformación se puede ejecutar correctamente con los valores que ha especificado el usuario. En este ejemplo, el código de esta clase sustituye la implementación predeterminada del método llamado isSourceElementValid, el cual devuelve true sólo si el origen de la transformación es un proyecto. Una implementación más robusta puede comprobar que el usuario haya seleccionado un proyecto UML.

En el siguiente fragmento de código se muestra la versión predeterminada del método isSourceElementValid que genera una transformación.

    /**
     * <!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @see com.ibm.xtools.transform.authoring.TransformationValidator#isSourceElementValid(java.lang.Object)
     * @generated
     */
    protected boolean isSourceElementValid(Object source) {
    	//Remove @generated tag to add more source validation checks
    	return super.isSourceElementValid(source);
    }
En el siguiente fragmento de código se muestra una versión personalizada de este método, que en el ejemplo siempre devuelve true:
    /**
     * <!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @see com.ibm.xtools.transform.authoring.TransformationValidator#isSourceElementValid(java.lang.Object)
     * @generated NOT
     */
    protected boolean isSourceElementValid(Object source) {
    	return source instanceof IProject;
    }

Personalización de la clase de proveedor de la transformación

En la clase de proveedor de transformación Project4sourceTransformationProvider, la implementación predeterminada del método createRootTransformation crea instancias de un objeto llamado RootTransformation, el cual crea instancias de la implementación predeterminada de la clase ResourceTransform. La implementación predeterminada de la clase llamada ResourceTransform contiene los elementos siguientes:
  • Una implementación del método llamado ResourceContentsExtractor que abre un archivo de modelos y carga sus contenidos en la memoria
  • Una regla llamada ResourceTargetRule que inicializa el modelo de destino que genera la transformación
    Nota: Esta regla depende de la propiedad sourceModelType del contexto de la transformación. Si se cambia el valor predeterminado de la propiedad sourceModelType, se tendrán que personalizar también la regla llamada ResourceTargetRule y la implementación del método ResourceContentsExtractor.
En este ejemplo se describe una clase llamada ResourcesFromProjectTransform, que es una versión personalizada de la clase ResourceTransform. Esta clase personalizada crea instancias de las clases siguientes:
  • Una clase llamada ProjectContentsExtractor, que es una versión personalizada de la clase ResourceContentsExtractor
  • Una clase que se llama Project4sourceTargetRule, que es una versión personalizada de la clase ResourceTargetRule

En el siguiente fragmento de código se muestra la versión predeterminada del método createRootTransformation que genera una transformación:

    /**
     * Crea una transformación raíz. Aquí se pueden añadir más reglas de la transformación
     * <!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @param transform The root transformation
     * @generated
     */
    protected RootTransformation createRootTransformation(ITransformationDescriptor descriptor) {
        return new RootTransformation(descriptor, new MainTransform());
    }
En el siguiente fragmento de código se muestra la versión personalizada del método createRootTransformation:
    /**
     * Crea una transformación raíz. Aquí se pueden añadir más reglas de la transformación
     * <!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @param transform The root transformation
     * @generated NOT
     */
    protected RootTransformation createRootTransformation(ITransformationDescriptor descriptor) {
        return new RootTransformation(descriptor, new MainTransform()) {
            @Override
             protected void addInitialExtractor(Transform mainTransform) {
                add(new ResourceListExtractor(new ResourcesFromProjectTransform(mainTransform)));
             }};
    }

En el fragmento de código siguiente se muestra el código fuente de la transformación denominada ResourcesFromProjectTransform, que contiene un extractor denominado ProjectContentsExtractor y una regla llamada Project4sourceTargetRule.

    protected class ResourcesFromProjectTransform extends ResourceTransform {
        public ResourcesFromProjectTransform(Transform mainTransform) {
            super(Project4sourceMessages.ResourcesFromProjectTransform_id);
            setName(Project4sourceMessages.ResourcesFromProjectTransform_name);
            add(new Project4sourceTargetRule());
            add(new ProjectContentsExtractor(mainTransform));
        }
    }
    
    protected class ProjectContentsExtractor extends ResourceContentsExtractor {
        
        public static final String UML_MODEL_FILE_TYPE = "emx"; //$NON-NLS-1$
        
        public ProjectContentsExtractor(AbstractTransform transform) {
            super(transform);
            setName(Project4sourceMessages.ProjectContentsExtractor_name);
        }

        @Override
        public Collection<Model> execute(ITransformContext context) {
            final ResourceSet resourceSet = ((EditingDomain) context
.getPropertyValue(TransformAuthoringConstants.SOURCE_EDITING_DOMAIN)).getResourceSet();
            final Collection<Model> models = new BasicEList();
            Object source = context.getSource();
            if (source instanceof IProject) {
                IProject project = (IProject)source;
                IResourceVisitor visitor = new IResourceVisitor() {
                    @Override
                    public boolean visit(IResource resource) throws CoreException {
                        if (resource instanceof IProject || resource instanceof IFolder)
                            return true;
                        if (resource instanceof IFile) {
                            IFile file = (IFile)resource;
                            if (UML_MODEL_FILE_TYPE.equals(file.getFileExtension())) {
                                Resource modelResource = resourceSet.getResource(getPlatformURI(file), true);
                                for (Iterator<EObject> i = modelResource.getContents().iterator(); i.hasNext();) {
                                    EObject content = i.next();
                                    if (content instanceof Model)
                                        models.add((Model)content);
                                }
                            }
                        }
                        return false;
                    }                    
                };
                try {
                    project.accept(visitor);
                } catch (CoreException ce) {
                    Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
Project4sourceMessages.ProjectContentsExtractor_name, ce));
                }                   
            }
            return models;
        }

    }
    
    protected class Project4sourceTargetRule extends ResourceTargetRule {

        @Override
        protected Object createTarget(ITransformContext context) {
            if (context.getSource() instanceof IProject) {        
                Object targetContainer = context.getTargetContainer();        
                if (targetContainer instanceof Resource) {
                    return targetContainer;
                } else if (targetContainer instanceof IFile){
                    IFile targetFile = (IFile)targetContainer;
                    ValidateEditRule.addAffectedFile(context, targetFile);
                    ResourceSet resourceSet = ((EditingDomain) context
.getPropertyValue(TransformAuthoringConstants.TARGET_EDITING_DOMAIN)).getResourceSet();
                    return resourceSet.createResource(getPlatformURI(targetFile));
                }
            }
            return super.createTarget(context);
        }
        
    }

Comentarios