de.ovgu.featureide.featurehouse.FeatureHouseComposer.java Source code

Java tutorial

Introduction

Here is the source code for de.ovgu.featureide.featurehouse.FeatureHouseComposer.java

Source

/* FeatureIDE - A Framework for Feature-Oriented Software Development
 * Copyright (C) 2005-2013  FeatureIDE team, University of Magdeburg, Germany
 *
 * This file is part of FeatureIDE.
 * 
 * FeatureIDE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * FeatureIDE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with FeatureIDE.  If not, see <http://www.gnu.org/licenses/>.
 *
 * See http://www.fosd.de/featureide/ for further information.
 */
package de.ovgu.featureide.featurehouse;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.JavaProject;
import org.prop4j.Node;
import org.prop4j.NodeWriter;
import org.sat4j.specs.TimeoutException;

import AST.Problem;
import AST.Program;
import cide.gparser.ParseException;
import cide.gparser.TokenMgrError;

import composer.CmdLineInterpreter;
import composer.CompositionException;
import composer.FSTGenComposer;
import composer.FSTGenComposerExtension;
import composer.ICompositionErrorListener;
import composer.IParseErrorListener;
import composer.rules.meta.FeatureModelInfo;

import de.ovgu.cide.fstgen.ast.FSTNode;
import de.ovgu.cide.fstgen.ast.FSTTerminal;
import de.ovgu.featureide.core.IFeatureProject;
import de.ovgu.featureide.core.builder.ComposerExtensionClass;
import de.ovgu.featureide.core.builder.IComposerExtensionClass;
import de.ovgu.featureide.core.fstmodel.FSTClass;
import de.ovgu.featureide.core.fstmodel.FSTMethod;
import de.ovgu.featureide.core.fstmodel.FSTModel;
import de.ovgu.featureide.core.fstmodel.FSTRole;
import de.ovgu.featureide.featurehouse.errorpropagation.ErrorPropagation;
import de.ovgu.featureide.featurehouse.meta.FeatureIDEModelInfo;
import de.ovgu.featureide.featurehouse.meta.featuremodel.FeatureModelClassGenerator;
import de.ovgu.featureide.featurehouse.model.FeatureHouseModelBuilder;
import de.ovgu.featureide.fm.core.FMCorePlugin;
import de.ovgu.featureide.fm.core.Feature;
import de.ovgu.featureide.fm.core.FeatureModel;
import de.ovgu.featureide.fm.core.configuration.Configuration;
import de.ovgu.featureide.fm.core.editing.NodeCreator;
import de.ovgu.featureide.fm.core.io.UnsupportedModelException;
import de.ovgu.featureide.fm.core.job.AStoppableJob;
import fuji.CompilerWarningException;
import fuji.Composition;
import fuji.CompositionErrorException;
import fuji.FeatureDirNotFoundException;
import fuji.Main;
import fuji.SemanticErrorException;
import fuji.SyntacticErrorException;

/**
 * Composes files using FeatureHouse.
 * 
 * @author Tom Brosch
 */
// TODO set "Composition errors" like *.png could not be composed with *.png
@SuppressWarnings("restriction")
public class FeatureHouseComposer extends ComposerExtensionClass {

    /**
     * 
     */
    private static final String FINAL_METHOD = "\\final_method";
    /**
     * 
     */
    private static final String ORIGINAL = "\\original";
    /**
     * 
     */
    private static final String FINAL_CONTRACT = "\\final_contract";
    private static final FeatureHouseCorePlugin LOGGER = FeatureHouseCorePlugin.getDefault();
    private static final String CONTRACT_COMPOSITION_CONSECUTIVE_CONTRACT_REFINEMENT = "consecutive contract refinement";
    private static final String CONTRACT_COMPOSITION_EXPLICIT_CONTRACT_REFINEMENT = "explicit contract refinement";
    private static final String CONTRACT_COMPOSITION_CONTRACT_OVERRIDING = "contract overriding";
    private static final String CONTRACT_COMPOSITION_PLAIN_CONTRACTING = "plain contracting";
    private static final String CONTRACT_COMPOSITION_PLAIN_CONTRACT = "plain_contracting";
    private static final String CONTRACT_COMPOSITION_EXPLICIT_CONTRACTING = "explicit_contracting";
    private static final String CONTRACT_COMPOSITION_CONSECUTIVE_CONTRACTING = "consecutive_contracting";
    private static final String CONTRACT_COMPOSITION_CUMULATIVE_CONTRACT_REFINEMENT = "cumulative contract refinement";
    private static final String CONTRACT_COMPOSITION_CUMULATIVE_CONTRACTING = "cumulative_contracting";
    private static final String CONTRACT_COMPOSITION_CONJUNCTIVE_CONTRACT_REFINEMENT = "conjunctive contract refinement";
    private static final String CONTRACT_COMPOSITION_CONJUNCTIVE_CONTRACTING = "conjunctive_contracting";
    private static final String CONTRACT_COMPOSITION_METHOD_BASED_COMPOSITION = "method-based composition";
    private static final String CONTRACT_COMPOSITION_METHOD_BASED = "method_based";
    private static final String CONTRACT_COMPOSITION_NONE = "none";

    private enum compKeys {
        conjunctive_contract, consecutive_contract, cumulative_contract, final_contract, final_method
    }

    public static final String COMPOSER_ID = "de.ovgu.featureide.composer.featurehouse";

    private boolean useFuji = false;

    private FSTGenComposer composer;

    public FeatureHouseModelBuilder fhModelBuilder;

    private ErrorPropagation errorPropagation = null;

    private IParseErrorListener listener = createParseErrorListener();

    private IParseErrorListener createParseErrorListener() {
        return new IParseErrorListener() {

            @Override
            public void parseErrorOccured(ParseException e) {
                createBuilderProblemMarker(e.currentToken.next.endLine, e.getMessage());
            }
        };
    }

    private ICompositionErrorListener compositionErrorListener = createCompositionErrorListener();
    private AStoppableJob fuji;

    /**
     * @return
     */
    private ICompositionErrorListener createCompositionErrorListener() {
        return new ICompositionErrorListener() {

            @Override
            public void parseErrorOccured(CompositionException e) {
                FSTTerminal terminal = e.getTerminalB();

                if (e.getMessage().contains(ORIGINAL)) {
                    if (!e.getTerminalB().getBody().contains(ORIGINAL))
                        terminal = e.getTerminalA();
                }

                IFile file = null;
                int lineFile = -1;
                if (terminal != null) {
                    file = getFile(terminal);
                    lineFile = terminal.beginLine;

                    if (file != null) {
                        try {
                            IMarker marker = file.createMarker(FeatureHouseCorePlugin.BUILDER_PROBLEM_MARKER);
                            marker.setAttribute(IMarker.LINE_NUMBER, lineFile);
                            marker.setAttribute(IMarker.MESSAGE, e.getMessage());
                            marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
                        } catch (CoreException e2) {
                            LOGGER.logError(e2);
                        }
                    } else {
                        LOGGER.logError(new Exception("No file provided for: " + terminal.toString()));
                    }
                }

            }

            private IFile getFile(FSTTerminal terminal) {
                if (terminal == null) {
                    return null;
                }
                FSTNode fileNode = terminal.getParent();
                while (fileNode != null && !fileNode.getName().endsWith(".java")) {
                    fileNode = fileNode.getParent();
                }
                if (fileNode != null) {
                    FSTNode featureNode = fileNode.getParent();
                    return featureProject.getSourceFolder().getFolder(featureNode.getName())
                            .getFile(fileNode.getName());
                } else {
                    LOGGER.logError(new Exception("Java file could not be found for: " + terminal.toString()));
                    return null;
                }
            }
        };
    }

    @Override
    public boolean initialize(IFeatureProject project) {
        boolean supSuccess = super.initialize(project);
        fhModelBuilder = new FeatureHouseModelBuilder(project);
        createBuildStructure();
        return supSuccess && fhModelBuilder != null;
    }

    /**
     * Creates an error marker to the last error file.
     * 
     * @param line
     *            The line of the marker.
     * @param message
     *            The message.
     */
    protected void createBuilderProblemMarker(int line, String message) {
        message = detruncateString(message);
        try {
            IMarker marker = getErrorFile().createMarker(FeatureHouseCorePlugin.BUILDER_PROBLEM_MARKER);
            marker.setAttribute(IMarker.LINE_NUMBER, line);
            marker.setAttribute(IMarker.MESSAGE, message);
            marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
        } catch (CoreException e) {
            LOGGER.logError(e);
        }

    }

    /**
     * @param message
     *            The message
     * @return A substring of message that is smaller than 65535 bytes.
     */
    private static String detruncateString(String message) {
        byte[] bytes;
        try {
            bytes = message.getBytes(("UTF-8"));
            if (bytes.length > 65535)
                message = message.substring(0, 65535 / 2);

        } catch (UnsupportedEncodingException e) {
            LOGGER.logError(e);
        }
        return message;
    }

    /**
     * Gets the file containing the actual error.
     * 
     * @return The file.
     */
    protected IFile getErrorFile() {
        return featureProject.getProject().getWorkspace().getRoot()
                .findFilesForLocationURI(composer.getErrorFiles().getLast().toURI())[0];
    }

    /**
     * Removes line and column form the message of the TokenMgrError.<br>
     * Example message:<br>
     * -Lexical error at line 7, column 7. Encountered: <EOF> after : ""
     * 
     * @param message
     *            The message
     * @return message without "line i, column j."
     */
    private String getTokenMgrErrorMessage(String message) {
        if (!message.contains("line ") || !message.contains("Encountered"))
            return message;
        return message.substring(0, message.indexOf(" at ")) + " e"
                + message.substring(message.indexOf("ncountered:"));
    }

    /**
     * Gets the line of the message of the TokenMgrError.<br>
     * Example message:<br>
     * -Lexical error at line 7, column 7. Encountered: <EOF> after : ""
     * 
     * @param message
     *            The error message
     * @return The line
     */
    private int getTokenMgrErrorLine(String message) {
        if (!message.contains("line "))
            return -1;
        return Integer.parseInt(message.substring(message.indexOf("line ") + 5, message.indexOf(',')));
    }

    /**
     * Checks the current folder structure at the build folder and creates
     * folders if necessary.
     */
    private void createBuildStructure() {
        IProject p = featureProject.getProject();
        if (p != null) {
            IFolder sourcefolder = featureProject.getBuildFolder();
            if (sourcefolder != null) {
                if (!sourcefolder.exists()) {
                    try {
                        sourcefolder.create(true, true, null);
                    } catch (CoreException e) {
                        LOGGER.logError(e);
                    }
                }
                IFile conf = featureProject.getCurrentConfiguration();
                if (conf != null) {
                    String configName = conf.getName();
                    sourcefolder = sourcefolder.getFolder(configName.substring(0, configName.indexOf('.')));
                    if (!sourcefolder.exists()) {
                        try {
                            sourcefolder.create(true, true, null);
                        } catch (CoreException e) {
                            LOGGER.logError(e);
                        }
                        callCompiler();
                    }
                    // setJavaBuildPath(conf.getName().split("[.]")[0]);
                }
            }
        }
    }

    public void performFullBuild(IFile config) {
        assert (featureProject != null) : "Invalid project given";
        final String configPath = config.getRawLocation().toOSString();
        final String basePath = featureProject.getSourcePath();
        final String outputPath = featureProject.getBuildPath();

        if (configPath == null || basePath == null || outputPath == null)
            return;

        final SignatureSetter signatureSetter = new SignatureSetter();

        /*
         * Run fuji parallel to the build process.
         */
        //TODO: save useFuji persistently
        fuji(signatureSetter);

        createBuildFolder(config);
        setJavaBuildPath(config.getName().split("[.]")[0]);

        if (buildMetaProduct()) {
            if (IFeatureProject.META_MODEL_CHECKING_BDD_JAVA_JML
                    .equals(featureProject.getMetaProductGeneration())) {
                buildDefaultMetaProduct(configPath, basePath, outputPath);
            } else if (IFeatureProject.META_MODEL_CHECKING_BDD_JAVA
                    .equals(featureProject.getMetaProductGeneration())) {
                buildBDDMetaProduct(configPath, basePath, outputPath, "java");
            } else if (IFeatureProject.META_MODEL_CHECKING_BDD_C
                    .equals(featureProject.getMetaProductGeneration())) {
                buildBDDMetaProduct(configPath, basePath, outputPath, "c");
            } else {
                buildDefaultMetaProduct(configPath, basePath, outputPath);
            }
        } else {
            composer = new FSTGenComposer(false);
            composer.addCompositionErrorListener(compositionErrorListener);
            try {
                composer.run(getArguments(configPath, basePath, outputPath, getContractParameter()));
            } catch (TokenMgrError e) {

            }
        }
        buildFSTModel(configPath, basePath, outputPath);
        signatureSetter.setFstModel(featureProject.getFSTModel());

        checkContractComposition();

        callCompiler();
    }

    private void checkContractComposition() {
        try {
            deleteContractErrorMarkers();

            final FSTModel fstModel = featureProject.getFSTModel();
            if (fstModel == null) {
                return;
            }

            final String contractParameter = getContractParameter();
            if (!contractParameter.equals(CONTRACT_COMPOSITION_EXPLICIT_CONTRACTING)) {
                for (FSTClass c : fstModel.getClasses()) {
                    for (FSTRole r : c.getRoles()) {
                        for (FSTMethod m : r.getClassFragment().getMethods()) {
                            if (m.hasContract() && m.getContract().contains("original")) {
                                if (m.getCompKey().isEmpty()
                                        && contractParameter.equals(CONTRACT_COMPOSITION_METHOD_BASED)) {
                                    continue;
                                }
                                setContractErrorMarker(m, "Keyword original ignored. Contract composition set to "
                                        + contractParameter + ". Change to \"Explicit Contract Refinement\".");
                            }
                        }
                    }
                }
            }

            if (!contractParameter.equals(CONTRACT_COMPOSITION_METHOD_BASED)) {
                for (FSTClass c : fstModel.getClasses()) {
                    for (FSTRole r : c.getRoles()) {
                        for (FSTMethod m : r.getClassFragment().getMethods()) {
                            if (m.getCompKey().length() > 0)
                                setContractErrorMarker(m,
                                        ": Keyword " + m.getCompKey() + " ignored. Contract composition set to "
                                                + contractParameter + ". Change to \"method-based composition\".");
                        }
                    }
                }

            } else {
                final FeatureModel featureModel = featureProject.getFeatureModel();
                for (FSTClass c : fstModel.getClasses()) {
                    for (FSTRole r : c.getRoles()) {
                        Feature featureRole1 = featureModel.getFeature(r.getFeature().getName());
                        for (FSTMethod m : r.getClassFragment().getMethods()) {
                            final List<Feature> currentFeatureList = new LinkedList<Feature>();
                            final List<Feature> originalList = new LinkedList<Feature>();

                            currentFeatureList.add(new Feature(featureModel, r.getFeature().getName()));

                            for (final String feat : featureModel.getFeatureOrderList()) {
                                if (feat.equals(r.getFeature().getName())) {
                                    break;
                                }
                                final FSTRole rr = c.getRole(feat);
                                if (rr == null) {
                                    continue;
                                }
                                Feature featureRole2 = featureModel.getFeature(feat);
                                for (FSTMethod mm : rr.getClassFragment().getMethods()) {

                                    if (checkForOriginalInContract(m, mm)) {
                                        originalList.add(featureRole2);
                                    }

                                    if (checkForIllegitimateMethodRefinement(m, mm)) {
                                        List<Feature> finalMethodList = new LinkedList<Feature>();
                                        finalMethodList.add(featureRole2);
                                        if (!featureModel.getAnalyser().checkIfFeatureCombinationNotPossible(
                                                featureRole1, finalMethodList))
                                            setContractErrorMarker(m,
                                                    "keyword \"\\final_method\" found but possibly later refinement.");
                                    }

                                    if (checkForIllegitimateContract(m, mm)) {
                                        List<Feature> finalContractList = new LinkedList<Feature>();
                                        finalContractList.add(featureRole2);
                                        if (mm.getCompKey().contains(FINAL_CONTRACT)
                                                && !featureModel.getAnalyser().checkIfFeatureCombinationNotPossible(
                                                        new Feature(featureModel, r.getFeature().getName()),
                                                        finalContractList))
                                            setContractErrorMarker(m,
                                                    "keyword \"\\final_contract\" found but possibly later contract refinement.");
                                    }

                                    if (checkForIllegitimaterefinement(m, mm)) {
                                        LinkedList<Feature> treeDependencyList = new LinkedList<Feature>();
                                        treeDependencyList.add(featureRole2);
                                        if (!featureModel.getAnalyser().checkIfFeatureCombinationNotPossible(
                                                featureRole1, treeDependencyList))
                                            setContractErrorMarker(m,
                                                    "Contract with composition keyword " + mm.getCompKey()
                                                            + " possibily illegitimately redefined with keyword "
                                                            + m.getCompKey() + ".");
                                    }

                                }
                            }
                            if (m.getContract().contains(ORIGINAL) && !(!originalList.isEmpty()
                                    ? featureModel.getAnalyser().checkImplies(currentFeatureList, originalList)
                                    : false))
                                setContractErrorMarker(m,
                                        "keyword \"\\original\" found but no mandatory previous introduction.");
                        }
                    }
                }
            }
        } catch (CoreException e2) {
            LOGGER.logError(e2);
        } catch (TimeoutException e) {
            LOGGER.logError(e);
        }

    }

    /**
     * Check if there is an introductionary method contract for methods that
     * contain the keyword original in contract.
     */
    private boolean checkForOriginalInContract(FSTMethod m, FSTMethod mm) {
        return m.hasContract() && m.getContract().contains(ORIGINAL) && mm.getName().equals(m.getName())
                && mm.hasContract();
    }

    /**
     * Check if a method whose contract is marked with \final_method is
     * redefine.
     * 
     * 
     * @param m
     * @param mm
     * @return
     */
    private boolean checkForIllegitimateMethodRefinement(FSTMethod m, FSTMethod mm) {
        return mm.getCompKey().contains(FINAL_METHOD) && mm.getFullName().equals(m.getFullName());
    }

    /**
     * Check if a method whose contract is marked with \final_contract is
     * redefined.
     * 
     * @param m
     * @param mm
     * @return
     */
    private boolean checkForIllegitimateContract(FSTMethod m, FSTMethod mm) {
        return m.hasContract() && mm.getCompKey().contains(FINAL_CONTRACT)
                && mm.getFullName().equals(m.getFullName()) && mm.hasContract();
    }

    /**
     * Check if a method contract's composition technique is illegitimately
     * redefined with another technique.
     * 
     * @param m
     * @param mm
     * @return
     */
    private boolean checkForIllegitimaterefinement(FSTMethod m, FSTMethod mm) {
        return m.hasContract() && m.getCompKey().length() > 0 && mm.getCompKey().length() > 0
                && compKeys.valueOf(m.getCompKey().substring(1)).ordinal() > 0
                && mm.getFullName().equals(m.getFullName()) && compKeys.valueOf(mm.getCompKey().substring(1))
                        .ordinal() > compKeys.valueOf(m.getCompKey().substring(1)).ordinal();
    }

    /**
     * @throws CoreException
     */
    private void deleteContractErrorMarkers() throws CoreException {
        IFolder sourceFolder = featureProject.getComposer().hasFeatureFolder() ? featureProject.getSourceFolder()
                : featureProject.getBuildFolder();
        IMarker[] markers = sourceFolder.findMarkers(FeatureHouseCorePlugin.CONTRACT_MARKER, false,
                IResource.DEPTH_INFINITE);
        for (IMarker marker : markers) {
            marker.delete();
        }
    }

    /**
     * @param m
     * @throws CoreException
     */
    private void setContractErrorMarker(FSTMethod m, String message) throws CoreException {
        IMarker marker = m.getFile().createMarker(FeatureHouseCorePlugin.CONTRACT_MARKER);
        marker.setAttribute(IMarker.LINE_NUMBER, m.getLine());
        marker.setAttribute(IMarker.MESSAGE, m.getName() + ": " + message);
        marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
    }

    /**
     * @param configPath
     * @param basePath
     * @param outputPath
     */
    private void buildDefaultMetaProduct(final String configPath, final String basePath, final String outputPath) {
        new FeatureModelClassGenerator(featureProject);
        FSTGenComposerExtension.key = IFeatureProject.META_THEOREM_PROVING
                .equals(featureProject.getMetaProductGeneration())
                || IFeatureProject.META_MODEL_CHECKING_BDD_JAVA_JML
                        .equals(featureProject.getMetaProductGeneration());
        composer = new FSTGenComposerExtension();
        composer.addCompositionErrorListener(compositionErrorListener);
        FeatureModel featureModel = featureProject.getFeatureModel();
        List<String> featureOrderList = featureModel.getFeatureOrderList();
        // dead features should not be composed
        LinkedList<String> deadFeatures = new LinkedList<String>();
        for (Feature deadFeature : featureModel.getAnalyser().getDeadFeatures()) {
            deadFeatures.add(deadFeature.getName());
        }

        String[] features = new String[featureOrderList.size()];
        int i = 0;
        for (String f : featureOrderList) {
            if (!deadFeatures.contains(f)) {
                features[i++] = f;
            }
        }

        try {
            String[] args = getArguments(configPath, basePath, outputPath, getContractParameter());
            long start = System.currentTimeMillis();
            FeatureModelInfo modelInfo = new FeatureIDEModelInfo(featureModel,
                    !IFeatureProject.META_THEOREM_PROVING.equals(featureProject.getMetaProductGeneration()));
            ((FSTGenComposerExtension) composer).setModelInfo(modelInfo);
            ((FSTGenComposerExtension) composer).buildMetaProduct(args, features);
            long end = System.currentTimeMillis();

            long duration = end - start;
            File file = new File("duration.txt");
            try {
                FileWriter writer = new FileWriter(file, true);
                writer.write(String.valueOf(duration));
                writer.write(System.getProperty("line.separator"));
                writer.flush();
                writer.close();
            } catch (IOException ex) {

            }
        } catch (TokenMgrError e) {
        } catch (Error e) {
            LOGGER.logError(e);
        }
    }

    private static String SPLModelChecker = "package verificationClasses;\r\n"
            + "import gov.nasa.jpf.jvm.Verify;\r\n" + "public class SPLModelChecker {\r\n"
            + "\tpublic static boolean getBoolean() {\r\n" + "\t\treturn Verify.getBoolean(false);\r\n"
            + "\t}\r\n\r\n" + "\tpublic static int getIntMinMax(int min, int max) {\r\n"
            + "\t\treturn Verify.getInt(min, max);\r\n" + "\t}\r\n" + "}";

    /**
     * @param configPath
     * @param basePath
     * @param outputPath
     * @param language
     */
    @SuppressWarnings("deprecation")
    private void buildBDDMetaProduct(final String configPath, final String basePath, final String outputPath,
            String language) {
        composer = new FSTGenComposerExtension();
        composer.addCompositionErrorListener(compositionErrorListener);
        try {
            IFile cnfFile = featureProject.getSourceFolder().getFile("model.cnf");
            Node nodes = NodeCreator.createNodes(featureProject.getFeatureModel().clone()).toCNF();
            String input = nodes.toString(NodeWriter.javaSymbols);
            input = input.replaceAll("!", "! ");
            InputStream cnfSource = new ByteArrayInputStream(
                    input.getBytes(Charset.availableCharsets().get("UTF-8")));
            try {
                if (cnfFile.exists()) {
                    cnfFile.setContents(cnfSource, false, true, null);
                } else {
                    cnfFile.create(cnfSource, true, null);
                }
                cnfFile.setDerived(true);
            } catch (CoreException e) {
                LOGGER.logError(e);
            }

            String[] arguments = getArguments(configPath, basePath, outputPath, getContractParameter());
            String[] newArgs = new String[arguments.length + 1];
            int i = 0;
            for (String arg : arguments) {
                newArgs[i++] = arg;
            }
            newArgs[i] = CmdLineInterpreter.INPUT_OPTION_LIFTING + language;
            composer.run(newArgs);

            IFolder verificationClasses = featureProject.getBuildFolder()
                    .getFolder(featureProject.getCurrentConfiguration().getName().split("[.]")[0])
                    .getFolder("verificationClasses");
            verificationClasses.create(true, true, null);
            featureProject.getBuildFolder().refreshLocal(IResource.DEPTH_ONE, null);
            for (IResource res : featureProject.getBuildFolder().members()) {
                if (res.getName().equals("FeatureSwitches.java")) {
                    res.move(verificationClasses.getFile("FeatureSwitches.java").getFullPath(), true, null);
                }
            }

            IFile sPLModelCheckerFile = verificationClasses.getFile("SPLModelChecker.java");
            InputStream source = new ByteArrayInputStream(
                    SPLModelChecker.getBytes(Charset.availableCharsets().get("UTF-8")));
            try {
                if (sPLModelCheckerFile.exists()) {
                    sPLModelCheckerFile.setContents(source, false, true, null);
                } else {
                    sPLModelCheckerFile.create(source, true, null);
                }
                sPLModelCheckerFile.setDerived(true);
            } catch (CoreException e) {
                LOGGER.logError(e);
            }

        } catch (TokenMgrError e) {

        } catch (CoreException e) {
            LOGGER.logError(e);
        }
    }

    /**
     * Starts type checking with fuji in a background job.
     */
    private void fuji(final SignatureSetter signatureSetter) {
        if (!useFuji) {
            return;
        }
        if (fuji != null) {
            fuji.cancel();
            try {
                fuji.join();
            } catch (InterruptedException e) {
                FMCorePlugin.getDefault().logError(e);
            }
        }
        fuji = new AStoppableJob("Type checking " + featureProject.getProjectName() + " with fuji") {
            @Override
            protected boolean work() {
                try {
                    final Program ast = runFuji(featureProject);
                    signatureSetter.setFujiParameters(featureProject, ast);
                    return true;
                } catch (CompositionException e) {
                    FMCorePlugin.getDefault().logError(e);
                    return false;
                }
            }
        };
        fuji.addJobFinishedListener(signatureSetter);
        fuji.schedule();
    }

    /**
     * Runs the type checker fuji. synchronized because fuji use static fields,
     * and a parallel execution is not possible.
     * 
     * @param featureProject
     *            The feature project of the caller.
     */
    private synchronized static Program runFuji(IFeatureProject featureProject) throws CompositionException {
        String sourcePath = featureProject.getSourcePath();
        String[] fujiOptions = new String[] { "-" + Main.OptionName.CLASSPATH, getClassPaths(featureProject),
                "-" + Main.OptionName.PROG_MODE, "-" + Main.OptionName.COMPOSTION_STRATEGY,
                Main.OptionName.COMPOSTION_STRATEGY_ARG_FAMILY, "-typechecker", "-basedir", sourcePath };
        Program ast = null;
        try {
            FeatureModel fm = featureProject.getFeatureModel();
            fm.getAnalyser().setDependencies();

            Main fuji = new Main(fujiOptions, fm, featureProject.getFeatureModel().getConcreteFeatureNames());
            Composition composition = fuji.getComposition(fuji);
            ast = composition.composeAST();

            // run type check
            fuji.typecheckAST(ast);

            // parsing warnings
            for (Problem warn : fuji.getWarnings()) {
                createFujiMarker(warn.line(), warn.message(), warn.fileName(), IMarker.SEVERITY_WARNING,
                        featureProject);
            }

            // parsing errors
            for (Problem err : fuji.getErrors()) {
                String message = err.message();
                if (err.line() == -1) {
                    for (String fileName : err.fileName().split("[\n]")) {
                        // currently bad workaround @ fuji, but seems to work
                        String file = fileName.substring(0, fileName.lastIndexOf(":"));
                        int line = Integer.parseInt(fileName.substring(fileName.lastIndexOf(":") + 1));
                        createFujiMarker(line, message, file, IMarker.SEVERITY_ERROR, featureProject);
                    }
                } else {
                    createFujiMarker(err.line(), message, err.fileName(), IMarker.SEVERITY_ERROR, featureProject);
                }

            }
        } catch (CompositionErrorException e) {
            createFujiMarker(-1, e.getMessage(), featureProject.getSourceFolder(), IMarker.SEVERITY_ERROR,
                    featureProject);
        } catch (IllegalArgumentException e) {
            LOGGER.logError(e);
        } catch (org.apache.commons.cli.ParseException e) {
            LOGGER.logError(e);
        } catch (IOException e) {
            LOGGER.logError(e);
        } catch (FeatureDirNotFoundException e) {
            LOGGER.logError(e);
        } catch (SyntacticErrorException e) {
            LOGGER.logError(e);
        } catch (SemanticErrorException e) {
            LOGGER.logError(e);
        } catch (CompilerWarningException e) {
            LOGGER.logError(e);
        } catch (UnsupportedModelException e) {
            LOGGER.logError(e);
        }

        return ast;
    }

    private static String getClassPaths(IFeatureProject featureProject) {
        String classpath = "";
        String sep = System.getProperty("path.separator");
        try {
            JavaProject proj = new JavaProject(featureProject.getProject(), null);
            IJavaElement[] elements = proj.getChildren();
            for (IJavaElement e : elements) {
                String path = e.getPath().toOSString();
                if (path.contains(":")) {
                    classpath += sep + path;
                    continue;
                }
                IResource resource = e.getResource();
                if (resource != null && "jar".equals(resource.getFileExtension())) {
                    classpath += sep + resource.getRawLocation().toOSString();
                }
            }
        } catch (JavaModelException e) {

        }
        return classpath.length() > 0 ? classpath.substring(1) : classpath;
    }

    /**
     * Creates an marker for fuji type checks.
     * 
     * @param line
     *            The line number
     * @param message
     *            The message to disply
     * @param file
     *            The file path
     * @param severity
     *            The severity of the marker (IMarker.SEVERITY_*)
     */
    protected static void createFujiMarker(int line, String message, String file, int severity,
            IFeatureProject featureProject) {
        IFile iFile = featureProject.getProject().getWorkspace().getRoot()
                .findFilesForLocationURI(new File(file).toURI())[0];
        createFujiMarker(line, message, iFile, severity, featureProject);
    }

    /**
     * Creates an marker for fuji type checks.
     * 
     * @param line
     *            The line number
     * @param message
     *            The message to display
     * @param file
     *            The file
     * @param severity
     *            The severity of the marker (IMarker.SEVERITY_*)
     */
    private static void createFujiMarker(int line, String message, IResource file, int severity,
            IFeatureProject featureProject) {
        // TODO NEWLine does not work
        message = message.replace("\n", NEWLINE);
        try {
            IMarker marker = file.createMarker(FeatureHouseCorePlugin.BUILDER_PROBLEM_MARKER);
            marker.setAttribute(IMarker.LINE_NUMBER, line);
            marker.setAttribute(IMarker.MESSAGE, "fuji: " + message);
            marker.setAttribute(IMarker.SEVERITY, severity);
        } catch (CoreException e) {
            LOGGER.logError(e);
        }

    }

    /**
     * Creates the folder at the source path named the configuration.
     * 
     * @param config
     */
    private void createBuildFolder(IFile config) {
        IFolder buildFolder = featureProject.getBuildFolder().getFolder(config.getName().split("[.]")[0]);
        if (!buildFolder.exists()) {
            try {
                buildFolder.create(true, true, null);
                buildFolder.refreshLocal(IResource.DEPTH_ZERO, null);
            } catch (CoreException e) {
                LOGGER.logError(e);
            }
        }
    }

    /**
     * Sets the Java build path to the folder at the build folder, named like
     * the current configuration.
     * 
     * @param buildPath
     *            The name of the current configuration
     */
    private void setJavaBuildPath(String buildPath) {
        try {
            JavaProject javaProject = new JavaProject(featureProject.getProject(), null);
            IClasspathEntry[] classpathEntrys = javaProject.getRawClasspath();

            int i = 0;
            for (IClasspathEntry e : classpathEntrys) {
                if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                    IPath path = featureProject.getBuildFolder().getFolder(buildPath).getFullPath();

                    /** return if nothing has to be changed **/
                    if (e.getPath().equals(path)) {
                        return;
                    }

                    /** change the actual source entry to the new build path **/
                    ClasspathEntry changedEntry = new ClasspathEntry(e.getContentKind(), e.getEntryKind(), path,
                            e.getInclusionPatterns(), e.getExclusionPatterns(), e.getSourceAttachmentPath(),
                            e.getSourceAttachmentRootPath(), null, e.isExported(), e.getAccessRules(),
                            e.combineAccessRules(), e.getExtraAttributes());
                    classpathEntrys[i] = changedEntry;
                    javaProject.setRawClasspath(classpathEntrys, null);
                    return;
                }
                i++;
            }

            /**
             * case: there is no source entry at the class path add the source
             * entry to the classpath
             **/
            IFolder folder = featureProject.getBuildFolder().getFolder(buildPath);
            ClasspathEntry sourceEntry = new ClasspathEntry(IPackageFragmentRoot.K_SOURCE,
                    IClasspathEntry.CPE_SOURCE, folder.getFullPath(), new IPath[0], new IPath[0], null, null, null,
                    false, null, false, new IClasspathAttribute[0]);
            IClasspathEntry[] newEntrys = new IClasspathEntry[classpathEntrys.length + 1];
            System.arraycopy(classpathEntrys, 0, newEntrys, 0, classpathEntrys.length);
            newEntrys[newEntrys.length - 1] = sourceEntry;
            javaProject.setRawClasspath(newEntrys, null);
        } catch (JavaModelException e) {
            LOGGER.logError(e);
        }
    }

    /**
     * Builds the fst model.
     * 
     * @param configPath
     * @param basePath
     * @param outputPath
     */
    private void buildFSTModel(final String configPath, final String basePath, final String outputPath) {
        // build the fst model of the current product
        /**
         * It is necessary to also build the model of the current product,
         * because the line numbers of generated elements (e.g., methods) are
         * necessary for error propagation.
         **/
        fhModelBuilder.buildModel(composer.getFstnodes(), false);

        // build the complete fst model
        composer = new FSTGenComposerExtension();
        composer.addParseErrorListener(listener);
        List<String> featureOrder = featureProject.getFeatureModel().getConcreteFeatureNames();
        String[] features = new String[featureOrder.size()];
        int i = 0;
        for (String f : featureOrder) {
            features[i++] = f;
        }
        try {
            ((FSTGenComposerExtension) composer)
                    .buildFullFST(getArguments(configPath, basePath, outputPath, getContractParameter()), features);
        } catch (TokenMgrError e) {
            createBuilderProblemMarker(getTokenMgrErrorLine(e.getMessage()),
                    getTokenMgrErrorMessage(e.getMessage()));
        } catch (Error e) {
            LOGGER.logError(e);
        }
        ArrayList<FSTNode> fstnodes = composer.getFstnodes();
        if (fstnodes != null) {
            fhModelBuilder.buildModel(fstnodes, true);
        }
    }

    /**
     * Returns the arguments for FeatureHouse Composer with the given arguments.
     * 
     * @param configPath
     * @param basePath
     * @param outputPath
     * @param contract
     * @return
     */
    private String[] getArguments(final String configPath, final String basePath, final String outputPath,
            String contract) {
        return new String[] { CmdLineInterpreter.INPUT_OPTION_EQUATIONFILE, configPath,
                CmdLineInterpreter.INPUT_OPTION_BASE_DIRECTORY, basePath,
                CmdLineInterpreter.INPUT_OPTION_OUTPUT_DIRECTORY, outputPath + "/",
                CmdLineInterpreter.INPUT_OPTION_CONTRACT_STYLE, contract };
    }

    private String getContractParameter() {
        String contractComposition = featureProject.getContractComposition().toLowerCase(Locale.ENGLISH);
        if (CONTRACT_COMPOSITION_NONE.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_NONE;
        } else if (CONTRACT_COMPOSITION_PLAIN_CONTRACTING.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_PLAIN_CONTRACT;
        } else if (CONTRACT_COMPOSITION_CONTRACT_OVERRIDING.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_CONTRACT_OVERRIDING;
        } else if (CONTRACT_COMPOSITION_EXPLICIT_CONTRACT_REFINEMENT.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_EXPLICIT_CONTRACTING;
        } else if (CONTRACT_COMPOSITION_CONSECUTIVE_CONTRACT_REFINEMENT.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_CONSECUTIVE_CONTRACTING;
        } else if (CONTRACT_COMPOSITION_CUMULATIVE_CONTRACT_REFINEMENT.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_CUMULATIVE_CONTRACTING;
        } else if (CONTRACT_COMPOSITION_CONJUNCTIVE_CONTRACT_REFINEMENT.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_CONJUNCTIVE_CONTRACTING;
        } else if (CONTRACT_COMPOSITION_METHOD_BASED_COMPOSITION.equals(contractComposition)) {
            return CONTRACT_COMPOSITION_METHOD_BASED;
        }
        return CONTRACT_COMPOSITION_NONE;
    }

    /**
     * This job calls the compiler by touching the .classpath file of the
     * project.<br>
     * This is necessary after calling <code>setAsCurrentConfiguration</code>.
     */
    private void callCompiler() {
        Job job = new Job("Call compiler") {
            protected IStatus run(IProgressMonitor monitor) {
                IFile iClasspathFile = featureProject.getProject().getFile(".classpath");
                if (iClasspathFile.exists()) {
                    try {
                        iClasspathFile.touch(monitor);
                        iClasspathFile.refreshLocal(IResource.DEPTH_ZERO, monitor);
                    } catch (CoreException e) {
                        LOGGER.logError(e);
                    }
                }
                return Status.OK_STATUS;
            }
        };
        job.setPriority(Job.DECORATE);
        job.schedule();

    }

    /**
     * For <code>FeatureHouse<code> a clean does not remove the folder,
     * named like the current configuration at the build folder, 
     * to prevent build path errors.
     * 
     * @return always <code>false</code>
     */
    @Override
    public boolean clean() {
        if (featureProject == null || featureProject.getBuildFolder() == null) {
            return false;
        }
        IFile config = featureProject.getCurrentConfiguration();
        if (config == null) {
            return false;
        }
        try {
            for (IResource featureFolder : featureProject.getBuildFolder().members()) {
                if (featureFolder.getName().equals(config.getName().split("[.]")[0])) {
                    if (featureFolder instanceof IFolder) {
                        for (IResource res : ((IFolder) featureFolder).members()) {
                            res.delete(true, null);
                        }
                    } else {
                        featureFolder.delete(true, null);
                    }
                } else {
                    featureFolder.delete(true, null);
                }
            }
        } catch (CoreException e) {
            LOGGER.logError(e);
        }
        return false;
    }

    public static final LinkedHashSet<String> EXTENSIONS = createExtensions();

    private static LinkedHashSet<String> createExtensions() {
        LinkedHashSet<String> extensions = new LinkedHashSet<String>();
        extensions.add("java");
        extensions.add("cs");
        extensions.add("c");
        extensions.add("h");
        extensions.add("hs");
        extensions.add("jj");
        extensions.add("als");
        extensions.add("xmi");
        return extensions;
    }

    @Override
    public LinkedHashSet<String> extensions() {
        return EXTENSIONS;
    }

    @Override
    public ArrayList<String[]> getTemplates() {
        return TEMPLATES;
    }

    private static final ArrayList<String[]> TEMPLATES = createTempltes();

    private static ArrayList<String[]> createTempltes() {
        ArrayList<String[]> list = new ArrayList<String[]>(8);
        list.add(new String[] { "Alloy", "als", "module " + CLASS_NAME_PATTERN });
        list.add(new String[] { "C", "c", "" });
        list.add(new String[] { "C#", "cs", "public class " + CLASS_NAME_PATTERN + " {\n\n}" });
        list.add(new String[] { "Haskell", "hs", "module " + CLASS_NAME_PATTERN + " where \n{\n\n}" });
        list.add(JAVA_TEMPLATE);
        list.add(new String[] { "JavaCC", "jj",
                "PARSER_BEGIN(" + CLASS_NAME_PATTERN + ") \n \n PARSER_END(" + CLASS_NAME_PATTERN + ")" });
        list.add(new String[] { "UML", "xmi",
                "<?xml version = '1.0' encoding = 'UTF-8' ?> \n   <XMI xmi.version = '1.2' xmlns:UML = 'org.omg.xmi.namespace.UML'>\n\n</XMI>" });
        list.add(new String[] { "Jak", "jak", "/**\r\n * TODO description\r\n */\r\npublic " + REFINES_PATTERN
                + " class " + CLASS_NAME_PATTERN + " {\r\n\r\n}" });
        return list;
    }

    @Override
    public void postModelChanged() {
        checkContractComposition();
    }

    @Override
    public void postCompile(IResourceDelta delta, final IFile file) {
        super.postCompile(delta, file);
        try {
            if (!file.getWorkspace().isTreeLocked()) {
                file.refreshLocal(IResource.DEPTH_ZERO, null);
            }
            if (errorPropagation == null) {
                errorPropagation = ErrorPropagation.createErrorPropagation(file);
            }
            errorPropagation.addFile(file);
        } catch (CoreException e) {
            LOGGER.logError(e);
        }
    }

    @Override
    public int getDefaultTemplateIndex() {
        return 4;
    }

    @Override
    public void buildFSTModel() {
        if (featureProject == null) {
            return;
        }
        final String configPath;
        IFile currentConfiguration = featureProject.getCurrentConfiguration();
        if (currentConfiguration != null) {
            configPath = currentConfiguration.getRawLocation().toOSString();
        } else {
            configPath = featureProject.getProject().getFile(".project").getRawLocation().toOSString();
        }
        final String basePath = featureProject.getSourcePath();
        final String outputPath = featureProject.getBuildPath();
        if (configPath == null || basePath == null || outputPath == null)
            return;

        composer = new FSTGenComposerExtension();
        composer.addParseErrorListener(listener);

        List<String> featureOrderList = featureProject.getFeatureModel().getConcreteFeatureNames();
        String[] features = new String[featureOrderList.size()];
        int i = 0;
        for (String f : featureOrderList) {
            features[i++] = f;
        }

        try {
            ((FSTGenComposerExtension) composer)
                    .buildFullFST(getArguments(configPath, basePath, outputPath, getContractParameter()), features);
        } catch (TokenMgrError e) {
            createBuilderProblemMarker(getTokenMgrErrorLine(e.getMessage()),
                    getTokenMgrErrorMessage(e.getMessage()));
        } catch (Error e) {
            LOGGER.logError(e);
        }

        ArrayList<FSTNode> fstnodes = composer.getFstnodes();
        if (fstnodes != null) {
            fhModelBuilder.buildModel(fstnodes, false);
            fstnodes.clear();
        }
    }

    @Override
    public void buildConfiguration(IFolder folder, Configuration configuration, String congurationName) {
        String folderName = folder.getName();
        super.buildConfiguration(folder, configuration, folderName);
        IFile configurationFile = folder.getFile(folderName + '.' + getConfigurationExtension());
        FSTGenComposer composer = new FSTGenComposer(false);
        composer.addParseErrorListener(createParseErrorListener());
        composer.addCompositionErrorListener(createCompositionErrorListener());
        composer.run(getArguments(configurationFile.getRawLocation().toOSString(), featureProject.getSourcePath(),
                folder.getParent().getLocation().toOSString(), getContractParameter()));
        if (errorPropagation != null && errorPropagation.job != null) {
            /*
             * Waiting for the propagation job to finish, because the
             * corresponding FSTModel is necessary for propagation at FH This is
             * in general no problem because the compiler is much faster then
             * the composer
             */
            try {
                errorPropagation.job.join();
            } catch (InterruptedException e) {
                LOGGER.logError(e);
            }
        }
        fhModelBuilder.buildModel(composer.getFstnodes(), false);
        if (!configurationFile.getName().startsWith(congurationName)) {
            try {
                configurationFile.move(
                        ((IFolder) configurationFile.getParent())
                                .getFile(congurationName + '.' + getConfigurationExtension()).getFullPath(),
                        true, null);
            } catch (CoreException e) {
                LOGGER.logError(e);
            }
        }
    }

    /**
     * FeatureHouse causes access violation errors if it is executed parallel.
     */
    @Override
    public boolean canGeneratInParallelJobs() {
        return false;
    }

    public static final QualifiedName BUILD_META_PRODUCT = new QualifiedName(
            FeatureHouseComposer.class.getName() + "#BuildMetaProduct",
            FeatureHouseComposer.class.getName() + "#BuildMetaProduct");
    public static final QualifiedName VERIFY_PRODUCT = new QualifiedName(
            FeatureHouseComposer.class.getName() + "#VerifyProduct",
            FeatureHouseComposer.class.getName() + "#VerifyProduct");
    private static final String TRUE = "true";

    public final boolean buildMetaProduct() {
        try {
            return TRUE.equals(featureProject.getProject().getPersistentProperty(BUILD_META_PRODUCT));
        } catch (CoreException e) {
            FMCorePlugin.getDefault().logError(e);
        }
        return false;
    }

    @Override
    public boolean hasContractComposition() {
        return true;
    }

    @Override
    public boolean hasMetaProductGeneration() {
        return true;
    }

    @Override
    public void copyNotComposedFiles(Configuration config, IFolder destination) {
        if (destination == null) {
            super.copyNotComposedFiles(config, featureProject.getBuildFolder()
                    .getFolder(featureProject.getCurrentConfiguration().getName().split("[.]")[0]));
        } else {
            // case: build into an external project
            super.copyNotComposedFiles(config, destination);
        }
    }

    @Override
    public Mechanism getGenerationMechanism() {
        return IComposerExtensionClass.Mechanism.FEATURE_ORIENTED_PROGRAMMING;
    }

    public void setUseFuji(boolean useFuji) {
        this.useFuji = useFuji;

        if (useFuji) {
            final IFile currentConfiguration = featureProject.getCurrentConfiguration();
            if (currentConfiguration != null) {
                performFullBuild(currentConfiguration);
            }
        }
    }

    public boolean usesFuji() {
        return useFuji;
    }
}