org.splevo.refactoring.VariabilityRefactoringService.java Source code

Java tutorial

Introduction

Here is the source code for org.splevo.refactoring.VariabilityRefactoringService.java

Source

/*******************************************************************************
 * Copyright (c) 2014
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Benjamin Klatt
 *    Daniel Kojic
 *******************************************************************************/
package org.splevo.refactoring;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.splevo.refactoring.RecommenderResult.Status;
import org.splevo.vpm.realization.VariabilityMechanism;
import org.splevo.vpm.software.SoftwareElement;
import org.splevo.vpm.variability.VariationPoint;
import org.splevo.vpm.variability.VariationPointGroup;
import org.splevo.vpm.variability.VariationPointModel;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

/**
 * A service to refactor the product copies described by a variation point model according to the
 * defined variation points and consolidating their implementations by introducing variability
 * mechanisms.
 */
public class VariabilityRefactoringService {

    public static final String JAVA_SOURCE_DIRECTORY = "JaMoPP.Refactoring.Options.SourceDirectory";
    public static final String SPLEVO_PROJECT = "SPLEVO_PROJECT";

    private static Logger logger = Logger.getLogger(VariabilityRefactoringService.class);

    /**
     * Perform refactoring according to the the configured {@link VariationPointModel}. This method
     * executes the {@link VariabilityRefactoring#refactor(VariationPoint, Map)} method.
     * 
     * @param variationPointModel
     *            The {@link VariationPointModel} containing the variation points with the intended
     *            variability mechanism.
     * @param refactoringConfigurations
     *            Refactoring configurations.
     */
    public void refactor(VariationPointModel variationPointModel, Map<String, Object> refactoringConfigurations) {
        preprocessResources(variationPointModel);
        EcoreUtil.resolveAll(variationPointModel);
        preprocessVPM(variationPointModel);
        Set<Resource> toBeSaved = new HashSet<Resource>();
        for (VariationPointGroup vpGroup : variationPointModel.getVariationPointGroups()) {

            for (VariationPoint variationPoint : vpGroup.getVariationPoints()) {
                String refactoringID = variationPoint.getVariabilityMechanism().getRefactoringID();
                VariabilityRefactoring refactoring = VariabilityRefactoringRegistry.getInstance()
                        .getElementById(refactoringID);

                if (refactoring.canBeAppliedTo(variationPoint).getSeverity() != Diagnostic.OK) {
                    logger.debug("Recommended refactoring cannot be applied to this variation point.");
                    continue;
                }

                List<Resource> changedResources = refactoring.refactor(variationPoint, refactoringConfigurations);

                toBeSaved.addAll(changedResources);
            }
        }

        postprocess(variationPointModel, toBeSaved);
    }

    /**
     * Perform refactoring according to the the configured {@link VariationPointModel}. This method
     * executes the {@link VariabilityRefactoring#refactor(VariationPoint, Map)} method.
     * 
     * <p>
     * <b>This method shall only be called from semi-automated refactorings that want to execute a
     * fully-automated refactoring as part of their workflow.</b>
     * </p>
     * 
     * @param refactoring
     *            The refactoring to be executed (has to be of type
     *            {@link FullyAutomatedVariabilityRefactoring})
     * @param vpm
     *            The variation point model to which the variation point belongs.
     * @param variationPoint
     *            The variation point to be refactored.
     * @param refactoringConfigurations
     *            The refactoring configuration to be used.
     * @throws VariabilityRefactoringFailedException
     *             Thrown if the refactoring is not applicable or not of type
     *             {@link FullyAutomatedVariabilityRefactoring}.
     */
    public void refactorFullyAutomated(VariabilityRefactoring refactoring, VariationPointModel vpm,
            VariationPoint variationPoint, Map<String, Object> refactoringConfigurations)
            throws VariabilityRefactoringFailedException {
        if (refactoring.canBeAppliedTo(variationPoint).getSeverity() != Diagnostic.OK) {
            throw new VariabilityRefactoringFailedException(
                    "Recommended refactoring cannot be applied to this variation point.");
        }

        if (!(refactoring instanceof FullyAutomatedVariabilityRefactoring)) {
            throw new VariabilityRefactoringFailedException(
                    "The given refactoring is no fully automated refactoring.");
        }

        List<Resource> changedResources = refactoring.refactor(variationPoint, refactoringConfigurations);

        postprocess(vpm, Sets.newHashSet(changedResources));
    }

    /**
     * Perform refactoring according to the the configured {@link VariationPointModel}. This method
     * executes the
     * {@link SemiAutomatedVariabilityRefactoring#startManualRefactoring(VariationPoint, Map)}
     * method after determining the refactoring that shall be applied from the variation point.
     * 
     * @param vpm
     *            The variation point model to which the variation point belongs.
     * @param variationPoint
     *            The variation point to be refactored.
     * @param refactoringConfigurations
     *            The refactoring configuration to be used.
     * @throws VariabilityRefactoringFailedException
     *             Thrown if the refactoring is not applicable, the type is not
     *             {@link SemiAutomatedVariabilityRefactoring}, or the execution of the refactoring
     *             failed.
     */
    public void refactorSemiAutomated(VariationPointModel vpm, VariationPoint variationPoint,
            Map<String, Object> refactoringConfigurations) throws VariabilityRefactoringFailedException {

        String refactoringID = variationPoint.getVariabilityMechanism().getRefactoringID();
        VariabilityRefactoring refactoring = VariabilityRefactoringRegistry.getInstance()
                .getElementById(refactoringID);

        if (refactoring.canBeAppliedTo(variationPoint).getSeverity() != Diagnostic.OK) {
            throw new VariabilityRefactoringFailedException(
                    "Recommended refactoring cannot be applied to this variation point.");
        }

        if (!(refactoring instanceof SemiAutomatedVariabilityRefactoring)) {
            throw new VariabilityRefactoringFailedException(
                    "The given refactoring is no fully automated refactoring.");
        }

        List<Resource> changedResources = ((SemiAutomatedVariabilityRefactoring) refactoring)
                .startManualRefactoring(variationPoint, refactoringConfigurations);

        postprocess(vpm, Sets.newHashSet(changedResources));
    }

    private void postprocess(VariationPointModel variationPointModel, Set<Resource> toBeSaved) {
        EcoreUtil.resolveAll(variationPointModel);
        postprocessVPM(variationPointModel);
        saveVPM(variationPointModel);
        saveAndPostprocessResources(toBeSaved);
    }

    private void postprocessVPM(VariationPointModel variationPointModel) {
        new ResourceProcessorService().processVPMAfterRefactorings(variationPointModel);
    }

    private void saveAndPostprocessResources(Set<Resource> toBeSaved) {
        for (Resource resource : toBeSaved) {
            saveResource(resource);
        }

        postprocessResources(toBeSaved);

        for (Resource resource : toBeSaved) {
            saveResource(resource);
        }
    }

    private void postprocessResources(Set<Resource> toBeSaved) {
        new ResourceProcessorService().postprocessResources(toBeSaved);
    }

    private void preprocessVPM(VariationPointModel variationPointModel) {
        new ResourceProcessorService().processVPMBeforeRefactorings(variationPointModel);
        saveVPM(variationPointModel);
    }

    private void preprocessResources(VariationPointModel variationPointModel) {
        Iterable<Resource> resourcesOfAllSoftwareElements = Iterables
                .transform(variationPointModel.getSoftwareElements(), new Function<SoftwareElement, Resource>() {
                    @Override
                    public Resource apply(SoftwareElement arg0) {
                        return arg0.getWrappedElement().eResource();
                    }
                });
        Iterable<Resource> nonNullResources = Iterables.filter(resourcesOfAllSoftwareElements,
                Predicates.notNull());
        Set<Resource> resources = Sets.newHashSet(nonNullResources);
        new ResourceProcessorService().processResourcesBeforeRefactorings(resources);
    }

    /**
     * Auto assign the highest prioritized and matching variability mechanism to each not yet
     * assigned variation point.
     * 
     * @param variationPointModel
     *            The variation point model to assign the vps in.
     * @param refactorings
     *            The prioritized list of refactorings to be considered by the recommender.
     * @return The result of the recommendation run.
     */
    public RecommenderResult recommendMechanisms(VariationPointModel variationPointModel,
            List<VariabilityRefactoring> refactorings) {
        RecommenderResult result = new RecommenderResult();

        for (VariationPointGroup group : variationPointModel.getVariationPointGroups()) {
            for (VariationPoint vp : group.getVariationPoints()) {
                if (vp.getVariabilityMechanism() == null) {

                    VariabilityRefactoring bestRefactoring = getBestMatchingRefactoring(vp, refactorings);
                    if (bestRefactoring == null) {
                        result.getUnassignedVariationPoints().add(vp);
                        continue;
                    }
                    VariabilityMechanism mechanism = bestRefactoring.getVariabilityMechanism();
                    vp.setVariabilityMechanism(mechanism);
                }
            }
        }

        if (!saveVPM(variationPointModel)) {
            result.setStatus(Status.FAILED);
        }

        return result;
    }

    /**
     * Get the best matching refactoring from a priorized list of refactorings.
     * 
     * @param vp
     *            The vp to decide a refactoring for.
     * @param refactorings
     *            The priorized list of refactorings. Higher priorized first.
     * @return The best matching refactoring. Null if none could be found.
     */
    private VariabilityRefactoring getBestMatchingRefactoring(VariationPoint vp,
            List<VariabilityRefactoring> refactorings) {

        for (VariabilityRefactoring refactoring : refactorings) {
            if (refactoring.canBeAppliedTo(vp).getSeverity() == Diagnostic.OK) {
                return refactoring;
            }
        }
        return null;
    }

    private boolean saveVPM(VariationPointModel variationPointModel) {
        if (variationPointModel.eResource() != null) {
            return saveResource(variationPointModel.eResource());
        }
        logger.info("Variation Point Model without a resource");
        return true;
    }

    private boolean saveResource(Resource resource) {
        try {
            resource.save(null);
        } catch (IOException e) {
            logger.error("Could not save resource: " + resource.getURI().lastSegment(), e);
            return false;
        }
        return true;
    }

}