Details for a model-to-model transformation that specifies a project as its source

You can modify the generated source code for a model-to-model transformation so that users can specify a project that contains multiple models as the source of the transformation.
Typically, a transformation user specifies one model as the source of a model-to-model transformation, because, by default, a model-to-model transformation accepts one model as input. This sample shows how to customize the generated transformation code so that transformation users can specify an Eclipse project instead of a model file as the transformation source, and the custom code determines which models in the project to transform. The UML models that have .emx as a file name extension in the designated project are collected at transformation run time, instead of when the user configures the transformation, and are used as input to the transformation.
Note: In this sample, the order that the transformation processes the source models does not matter. To process the models in a specific order, add the corresponding code to your implementation of the class named ProjectContentsExtractor.

This sample contains a transformation mapping model that defines basic mappings for UML models, packages, and classes. The generated transformation creates a UML model that has the same name as the source project, and, in that model, creates a package for each UML model that the source project contains. For each class in the corresponding UML source model, the transformation also creates a class in each package. Although this mapping model is simple, the generated transformation shows how you must customize the code to support specifying source models by specifying a source project.

This sample shows how to customize the following items in the generated transformation:

Customization of the generated plugin.xml file

In the plugin.xml file, in the transformation extension point, the property named sourceModelType specifies the type of objects that a transformation user can specify as the transformation source. When you create a model-to-model transformation project, by default, this property value is set to resource, which means that in the transformation configuration wizard and editor, a transformation user must specify an existing file in the workspace as the transformation source. When you set the value of the sourceModelType property to project, a transformation user can specify an Eclipse project, instead of a file, as the transformation source.

Customization of the transformation validator class

The transformation configuration wizard and editor use the transformation validator class to verify that the transformation can run correctly with the settings that the user specifies. In the transformation validator class, the default implementation of the method named isSourceElementValid returns true only if the specified transformation source is a file.

In this sample, the transformation validator class named Project4sourceTransformationValidator verifies that the transformation can run correctly with the settings that the user specifies. For this sample, the code in this class overrides the default implementation of the method named isSourceElementValid, and the method returns true only if the transformation source is a project. A more robust implementation might check to see that the user selected a UML project.

The following code fragment shows the default version of the isSourceElementValid method that a transformation generates:

    /**
     * <!-- 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);
    }
The following code fragment shows a customized version of this method, which, for the purposes of this sample, always returns 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;
    }

Customization of the transformation provider class

In the transformation provider class named Project4sourceTransformationProvider, the default implementation of the method named createRootTransformation instantiates an object named RootTransformation, which instantiates the default implementation of the class named ResourceTransform. The default implementation of the class named ResourceTransform contains the following items:
  • An implementation of the method named ResourceContentsExtractor that opens a model file and loads its contents into memory
  • A rule named ResourceTargetRule that initializes the target model that the transformation generates
    Note: This rule depends on the sourceModelType property in the transformation context: if you change the default value of the property named sourceModelType, then you should also customize the rule named ResourceTargetRule, and the implementation of the method named ResourceContentsExtractor.
This sample defines a class named ResourcesFromProjectTransform, which is a customized version of the class named ResourceTransform. This customized class instantiates the following classes:
  • A class named ProjectContentsExtractor, which is a customized version of the class named ResourceContentsExtractor
  • A class named Project4sourceTargetRule, which is a customized version of the class named ResourceTargetRule

The following code fragment shows the default version of the method named createRootTransformation that a transformation generates:

    /**
     * Creates a root transformation. You may add more rules to the transformation here
     * <!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @param transform The root transformation
     * @generated
     */
    protected RootTransformation createRootTransformation(ITransformationDescriptor descriptor) {
        return new RootTransformation(descriptor, new MainTransform());
    }
The following code fragment shows the customized version of the method named createRootTransformation:
    /**
     * Creates a root transformation. You may add more rules to the transformation here
     * <!-- 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)));
             }};
    }

The following code fragment shows the source code for the transform named ResourcesFromProjectTransform, which contains an extractor named ProjectContentsExtractor, and a rule named 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);
        }
        
    }

Feedback