fr.obeo.intent.specification.parser.SpecificationParser.java Source code

Java tutorial

Introduction

Here is the source code for fr.obeo.intent.specification.parser.SpecificationParser.java

Source

/*****************************************************************************
 * Copyright (c) 2013 Obeo.
 * 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:
 *     Obeo - initial API and implementation
 *****************************************************************************/
package fr.obeo.intent.specification.parser;

import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.UnmodifiableIterator;

import fr.obeo.intent.specification.Action;
import fr.obeo.intent.specification.AutomationLayer;
import fr.obeo.intent.specification.Behaviour;
import fr.obeo.intent.specification.Benefit;
import fr.obeo.intent.specification.Capability;
import fr.obeo.intent.specification.Context;
import fr.obeo.intent.specification.Feature;
import fr.obeo.intent.specification.NamedElement;
import fr.obeo.intent.specification.Parameter;
import fr.obeo.intent.specification.Role;
import fr.obeo.intent.specification.Scenario;
import fr.obeo.intent.specification.ScenarioElement;
import fr.obeo.intent.specification.Specification;
import fr.obeo.intent.specification.SpecificationFactory;
import fr.obeo.intent.specification.Story;
import fr.obeo.intent.specification.TestGenerationNote;
import fr.obeo.intent.specification.TestType;
import fr.obeo.intent.specification.Value;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl;
import org.eclipse.mylyn.docs.intent.collab.common.query.ModelingUnitQuery;
import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter;
import org.eclipse.mylyn.docs.intent.core.document.IntentSection;
import org.eclipse.mylyn.docs.intent.core.modelingunit.ExternalContentReference;
import org.eclipse.mylyn.docs.intent.core.modelingunit.ModelingUnit;
import org.eclipse.mylyn.docs.intent.core.modelingunit.ModelingUnitFactory;
import org.eclipse.mylyn.docs.intent.external.parser.contribution.ExternalParserCompletionProposal;
import org.eclipse.mylyn.docs.intent.external.parser.contribution.IExternalParser;

/**
 * This parser is able to parse the specification syntax and create the
 * corresponding specification model.
 * 
 * @author <a href="mailto:melanie.bats@obeo.fr">Melanie Bats</a>
 */
public class SpecificationParser implements IExternalParser {
    private static final String VARIABLE = "$";

    private static final String AROBASE = "@";

    /**
     * Comma.
     */
    private static final String COMMA = ",";

    /**
     * Closed bracket.
     */
    private static final String CLOSE_BRACKET = "]";

    /**
     * Opened bracket.
     */
    private static final String OPEN_BRACKET = "[";

    /**
     * Colon.
     */
    private static final String COLON = ":";

    /**
     * Specification factory.
     */
    private SpecificationFactory specificationFactory = SpecificationFactory.eINSTANCE;

    /**
     * Specification.
     */
    private Specification specification;

    /**
     * Automation layer.
     */
    private AutomationLayer automationLayer;

    /**
     * List of parsed elements.
     */
    private List<ParsedElement> parsedElements = Lists.newArrayList();

    /**
     * Resource set.
     */
    private ResourceSet resourceSet;

    /**
     * Specification resource.
     */
    private Resource resource;

    /**
     * Specification parser keywords.
     */
    private enum SpecificationKeyword {
        FEATURE("Feature"), STORY("Story"), AS("As"), I_WANT("I want"), SO_THAT("So that"), SCENARIO(
                "Scenario"), GIVEN("Given"), WHEN("When"), THEN("Then");

        /**
         * Value.
         */
        protected String value;

        /**
         * Default constructor.
         * 
         * @param value
         *            Value
         */
        private SpecificationKeyword(String value) {
            this.value = value;
        }
    }

    /**
     * Default constructor.
     */
    public SpecificationParser() {
        resourceSet = new ResourceSetImpl();
        init();
    }

    @Override
    public void parse(IntentSection intentSection, String descriptionUnitToParse) {
        // Only parse sections with a title
        if (intentSection.getTitle() != null) {
            // Get valid elements
            StringBuffer validElements = new StringBuffer();
            for (String element : Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings()
                    .split(descriptionUnitToParse)) {
                if (isValidElement(element)) {
                    validElements.append(element + "\n");
                }
            }

            // Parse features
            parseFeatures(intentSection, validElements);

            // Parse stories
            parseStories(intentSection, validElements);

            // Parse scenarios
            parseScenarios(intentSection, validElements);
        }
    }

    /**
     * Parse the stories.
     * 
     * @param intentSection
     *            Intent Section
     * @param validElements
     *            Valid elements
     */
    private void parseStories(final IntentSection intentSection, final StringBuffer validElements) {
        // Get valid stories
        StringBuffer validStories = new StringBuffer();
        for (String element : Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings().split(validElements)) {
            if (isStory(element)) {
                validStories.append(element + "\n");
            }
        }

        // "Story:"
        final String storyPattern = SpecificationKeyword.STORY.value + COLON;
        for (String description : Splitter.onPattern(storyPattern).trimResults().omitEmptyStrings()
                .split(validStories)) {
            Map<String, String> result = Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings()
                    .withKeyValueSeparator(COLON).split(storyPattern + description);
            String storyDescription = result.get(SpecificationKeyword.STORY.value);

            final String storyName = storyDescription.substring(0, storyDescription.indexOf(OPEN_BRACKET)).trim();

            NamedElement namedElement = getNamedElement(storyName, Story.class);
            Story story = null;
            if (namedElement == null) {
                story = specificationFactory.createStory();
                story.setName(storyName);
                specification.getStories().add((Story) story);
                parsedElements.add(new ParsedElement(intentSection, story));
            } else if (namedElement instanceof Story) {
                story = (Story) namedElement;
            } else {
                throw new UnsupportedOperationException();
            }

            String features = storyDescription.substring(storyDescription.indexOf(OPEN_BRACKET) + 1,
                    storyDescription.indexOf(CLOSE_BRACKET));
            for (String featureName : Splitter.on(COMMA).trimResults().omitEmptyStrings().split(features)) {
                namedElement = getNamedElement(featureName, Feature.class);
                Feature feature = null;
                if (namedElement == null) {
                    feature = specificationFactory.createFeature();
                    feature.setName(featureName);
                    specification.getFeatures().add(feature);
                    parsedElements.add(new ParsedElement(intentSection, feature));
                } else if (namedElement instanceof Feature) {
                    feature = (Feature) namedElement;
                } else {
                    throw new UnsupportedOperationException();
                }
                feature.getStories().add((Story) story);
            }

            if (result.containsKey(SpecificationKeyword.AS.value)) {
                String roleName = result.get(SpecificationKeyword.AS.value).trim();
                namedElement = getNamedElement(roleName, Role.class);
                Role role = null;
                if (namedElement == null) {
                    role = specificationFactory.createRole();
                    role.setName(roleName);
                    specification.getRoles().add(role);
                } else if (namedElement instanceof Role) {
                    role = (Role) namedElement;
                } else {
                    throw new UnsupportedOperationException();
                }
                story.setAs(role);

                String capabilityName = result.get(SpecificationKeyword.I_WANT.value).trim();
                namedElement = getNamedElement(capabilityName, Capability.class);
                Capability capability = null;
                if (namedElement == null) {
                    capability = specificationFactory.createCapability();
                    capability.setName(capabilityName);
                    specification.getCapabilities().add(capability);
                } else if (namedElement instanceof Capability) {
                    capability = (Capability) namedElement;
                } else {
                    throw new UnsupportedOperationException();
                }
                story.setIWant(capability);

                String benefitName = result.get(SpecificationKeyword.SO_THAT.value).trim();
                namedElement = getNamedElement(benefitName, Benefit.class);
                Benefit benefit = null;
                if (namedElement == null) {
                    benefit = specificationFactory.createBenefit();
                    benefit.setName(benefitName);
                    specification.getBenefits().add(benefit);
                } else if (namedElement instanceof Benefit) {
                    benefit = (Benefit) namedElement;
                } else {
                    throw new UnsupportedOperationException();
                }
                story.setSoThat(benefit);
            }
        }
    }

    private void parseScenarios(IntentSection intentSection, StringBuffer validElements) {
        // Get valid scenarios
        StringBuffer validScenarios = new StringBuffer();
        for (String element : Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings().split(validElements)) {
            if (isScenario(element)) {
                validScenarios.append(element + "\n");
            }
        }

        // "Scenario:"
        final String scenarioPattern = SpecificationKeyword.SCENARIO.value + COLON;
        for (String description : Splitter.onPattern(scenarioPattern).trimResults().omitEmptyStrings()
                .split(validScenarios)) {
            Iterable<String> results = Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings()
                    .split(scenarioPattern + description);
            Scenario scenario = null;
            for (String result : results) {
                if (result.startsWith(SpecificationKeyword.SCENARIO.value)) {
                    String scenarioDescription = Splitter.on(SpecificationKeyword.SCENARIO.value + COLON)
                            .trimResults().omitEmptyStrings().split(result).iterator().next();
                    // Scenario: Name [Parent Story]
                    final String scenarioName = scenarioDescription
                            .substring(0, scenarioDescription.indexOf(OPEN_BRACKET)).trim();

                    NamedElement namedElement = getNamedElement(scenarioName, Scenario.class);
                    if (namedElement == null) {
                        scenario = specificationFactory.createScenario();
                        scenario.setName(scenarioName);
                        parsedElements.add(new ParsedElement(intentSection, scenario));
                    } else if (namedElement instanceof Scenario) {
                        scenario = (Scenario) namedElement;
                    } else {
                        throw new UnsupportedOperationException();
                    }

                    // Scenario: Name [Parent Story] @ui
                    TestGenerationNote testNote = specificationFactory.createTestGenerationNote();
                    scenario.getNotes().add(testNote);
                    if (scenarioDescription.contains(AROBASE)) {
                        final String scenarioTestType = scenarioDescription
                                .substring(scenarioDescription.indexOf(AROBASE));
                        if (scenarioTestType.contains(TestType.UI.getName().toLowerCase())) {
                            testNote.setType(TestType.UI);
                        } else if (scenarioTestType.contains(TestType.UNIT.getName().toLowerCase())) {
                            testNote.setType(TestType.UNIT);
                        } else if (scenarioTestType.contains(TestType.PLUGIN.getName().toLowerCase())) {
                            testNote.setType(TestType.PLUGIN);
                        }
                    }

                    String stories = scenarioDescription.substring(scenarioDescription.indexOf(OPEN_BRACKET) + 1,
                            scenarioDescription.indexOf(CLOSE_BRACKET));
                    for (String storyName : Splitter.on(COMMA).trimResults().omitEmptyStrings().split(stories)) {
                        namedElement = getNamedElement(storyName, Story.class);
                        Story story = null;
                        if (namedElement == null) {
                            story = specificationFactory.createStory();
                            story.setName(storyName);
                            specification.getStories().add(story);
                            parsedElements.add(new ParsedElement(intentSection, story));
                        } else if (namedElement instanceof Story) {
                            story = (Story) namedElement;
                        } else {
                            throw new UnsupportedOperationException();
                        }
                        story.getScenarios().add(scenario);
                    }
                } else if (result.startsWith(SpecificationKeyword.GIVEN.value)) {
                    String contextName = null;
                    if (result.contains(VARIABLE)) {
                        contextName = Splitter.on(SpecificationKeyword.GIVEN.value + COLON).trimResults()
                                .omitEmptyStrings().split(result.substring(0, result.indexOf(VARIABLE))).iterator()
                                .next();
                    } else {
                        // Given: MyContext [ParentContext]
                        if (result.contains(OPEN_BRACKET)) {
                            contextName = Splitter.on(SpecificationKeyword.GIVEN.value + COLON).trimResults()
                                    .omitEmptyStrings().split(result.substring(0, result.indexOf(OPEN_BRACKET)))
                                    .iterator().next();
                        } else {
                            // Given: MyContext
                            contextName = Splitter.on(SpecificationKeyword.GIVEN.value + COLON).trimResults()
                                    .omitEmptyStrings().split(result).iterator().next();
                        }
                    }

                    Context parentContext = null;
                    // Given: MyContext [ParentContext]
                    if (result.contains(OPEN_BRACKET) && result.contains(CLOSE_BRACKET)) {
                        String parentContextName = result.substring(result.indexOf(OPEN_BRACKET) + 1,
                                result.indexOf(CLOSE_BRACKET));
                        NamedElement namedElement = getNamedElement(parentContextName, Context.class);
                        if (namedElement == null) {
                            parentContext = specificationFactory.createContext();
                            parentContext.setName(parentContextName);
                            automationLayer.getContext().add(parentContext);
                        } else if (namedElement instanceof Context) {
                            parentContext = (Context) namedElement;
                        }
                    }

                    NamedElement namedElement = getNamedElement(contextName, Context.class);
                    Context context = null;
                    if (namedElement == null) {
                        context = specificationFactory.createContext();
                        context.setName(contextName);
                        if (parentContext != null) {
                            context.getContexts().add(parentContext);
                        }
                        automationLayer.getContext().add(context);

                    } else if (namedElement instanceof Context) {
                        context = (Context) namedElement;
                    } else {
                        throw new UnsupportedOperationException();
                    }

                    parseParameters(result, context, scenario);
                    scenario.getGiven().add(context);
                } else if (result.startsWith(SpecificationKeyword.WHEN.value)) {
                    String actionName = null;
                    if (result.contains(VARIABLE)) {
                        actionName = Splitter.on(SpecificationKeyword.WHEN.value + COLON).trimResults()
                                .omitEmptyStrings().split(result.substring(0, result.indexOf(VARIABLE))).iterator()
                                .next();
                    } else {
                        actionName = Splitter.on(SpecificationKeyword.WHEN.value + COLON).trimResults()
                                .omitEmptyStrings().split(result).iterator().next();
                    }
                    NamedElement namedElement = getNamedElement(actionName, Action.class);
                    Action action = null;
                    if (namedElement == null) {
                        action = specificationFactory.createAction();
                        action.setName(actionName);
                        automationLayer.getActions().add(action);
                    } else if (namedElement instanceof Action) {
                        action = (Action) namedElement;
                    } else {
                        throw new UnsupportedOperationException();
                    }
                    parseParameters(result, action, scenario);

                    scenario.getWhen().add(action);
                } else if (result.startsWith(SpecificationKeyword.THEN.value)) {

                    String behaviourName = null;
                    if (result.contains(VARIABLE)) {
                        behaviourName = Splitter.on(SpecificationKeyword.THEN.value + COLON).trimResults()
                                .omitEmptyStrings().split(result.substring(0, result.indexOf(VARIABLE))).iterator()
                                .next();
                    } else {
                        behaviourName = Splitter.on(SpecificationKeyword.THEN.value + COLON).trimResults()
                                .omitEmptyStrings().split(result).iterator().next();
                    }
                    NamedElement namedElement = getNamedElement(behaviourName, Behaviour.class);
                    Behaviour behaviour = null;
                    if (namedElement == null) {
                        behaviour = specificationFactory.createBehaviour();
                        behaviour.setName(behaviourName);
                        automationLayer.getBehaviours().add(behaviour);
                    } else if (namedElement instanceof Behaviour) {
                        behaviour = (Behaviour) namedElement;
                    } else {
                        throw new UnsupportedOperationException();
                    }
                    parseParameters(result, behaviour, scenario);
                    scenario.getThen().add(behaviour);
                }
            }
        }
    }

    /**
     * Parse the parameters.
     * 
     * @param description
     *            Description to parse
     * @param element
     *            Parent scenario element
     * @param scenario
     */
    private void parseParameters(String description, ScenarioElement element, Scenario scenario) {
        // Given: Action $Variable1 $Variable2
        if (description.contains(VARIABLE)) {
            Iterable<String> params = Splitter.on(VARIABLE).omitEmptyStrings().split(description);
            // Ignore the first value as it is the action name
            Iterator<String> iter = params.iterator();
            iter.next();

            int count = 0;
            for (Iterator<String> iterator = iter; iterator.hasNext();) {
                String param = (String) iterator.next();
                String parameterName = element.getName() + count;
                Parameter parameter = getParameter(parameterName, element);
                if (parameter == null) {
                    parameter = specificationFactory.createParameter();
                    parameter.setName(parameterName);
                    element.getParameters().add(parameter);
                }
                Value value = specificationFactory.createValue();
                value.setValue(
                        param.substring(param.indexOf("'") + 1, param.lastIndexOf("'")).replaceAll("\\\\", ""));
                value.setParameter(parameter);
                scenario.getValues().add(value);
                count++;
            }
        }
    }

    private Parameter getParameter(final String parameterName, final ScenarioElement element) {
        UnmodifiableIterator<Parameter> it = Iterators.filter(element.getParameters().iterator(),
                new Predicate<Parameter>() {
                    public boolean apply(Parameter parameter) {
                        if (parameter != null && parameter instanceof Parameter) {
                            return parameterName.equals(((NamedElement) parameter).getName());
                        }
                        return false;
                    }
                });
        if (it.hasNext()) {
            return (Parameter) it.next();
        }
        return null;
    }

    /**
     * Text to parse : "Feature: MyFeature1
     * [ReferencedFeature1,ReferencedFeature2] Feature: MyFeature2
     * [ReferencedFeature2,ReferencedFeature3]"
     * 
     * @param intentSection
     * @param validElements
     * @return
     */
    private void parseFeatures(IntentSection intentSection, StringBuffer validElements) {
        // Get valid features
        StringBuffer validFeatures = new StringBuffer();
        for (String element : Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings().split(validElements)) {
            if (isFeature(element)) {
                validFeatures.append(element + "\n");
            }
        }

        // "Feature:"
        final String featurePattern = SpecificationKeyword.FEATURE.value + COLON;

        for (String description : Splitter.onPattern(featurePattern).trimResults().omitEmptyStrings()
                .split(validFeatures)) {
            Map<String, String> result = Splitter.onPattern("\r?\n").trimResults().omitEmptyStrings()
                    .withKeyValueSeparator(COLON).split(featurePattern + description);
            String featureDescription = result.get(SpecificationKeyword.FEATURE.value);
            String featureName;
            if (featureDescription.contains(OPEN_BRACKET)) {
                featureName = featureDescription.substring(0, featureDescription.indexOf(OPEN_BRACKET)).trim();
            } else {
                featureName = featureDescription;
            }
            NamedElement namedElement = getNamedElement(featureName, Feature.class);
            Feature feature = null;
            if (namedElement == null) {
                feature = specificationFactory.createFeature();
                feature.setName(featureName);
                specification.getFeatures().add((Feature) feature);
                parsedElements.add(new ParsedElement(intentSection, feature));
            } else if (namedElement instanceof Feature) {
                feature = (Feature) namedElement;
            } else {
                throw new UnsupportedOperationException();
            }

            if (featureDescription.contains(OPEN_BRACKET)) {
                String features = featureDescription.substring(featureDescription.indexOf(OPEN_BRACKET) + 1,
                        featureDescription.indexOf(CLOSE_BRACKET));
                for (String refFeatureName : Splitter.on(COMMA).trimResults().omitEmptyStrings().split(features)) {
                    namedElement = getNamedElement(refFeatureName, Feature.class);
                    Feature refFeature = null;
                    if (namedElement == null) {
                        refFeature = specificationFactory.createFeature();
                        refFeature.setName(refFeatureName);
                        specification.getFeatures().add(refFeature);
                        parsedElements.add(new ParsedElement(intentSection, refFeature));
                    } else if (namedElement instanceof Feature) {
                        refFeature = (Feature) namedElement;
                    } else {
                        throw new UnsupportedOperationException();
                    }
                    refFeature.getRefFeatures().add((Feature) feature);
                }
            }
        }
    }

    /**
     * Check if an element is a feature.
     * 
     * @param element
     *            Element
     * @return True if the element is a feature
     */
    private boolean isFeature(String element) {
        return element.startsWith(SpecificationKeyword.FEATURE.value);
    }

    /**
     * Check if an element is a story.
     * 
     * @param element
     *            Element
     * @return True if the element is a story
     */
    private boolean isStory(String element) {
        return element.startsWith(SpecificationKeyword.STORY.value)
                || element.startsWith(SpecificationKeyword.AS.value)
                || element.startsWith(SpecificationKeyword.I_WANT.value)
                || element.startsWith(SpecificationKeyword.SO_THAT.value);
    }

    /**
     * Check if an element is a scenario.
     * 
     * @param element
     *            Element
     * @return True if the element is a scenario
     */
    private boolean isScenario(String element) {
        return element.startsWith(SpecificationKeyword.SCENARIO.value)
                || element.startsWith(SpecificationKeyword.GIVEN.value)
                || element.startsWith(SpecificationKeyword.WHEN.value)
                || element.startsWith(SpecificationKeyword.THEN.value);
    }

    /**
     * Check if an element is a specification element (feature, story,
     * scenario...).
     * 
     * @param element
     *            Element
     * @return True if the element is a specification element
     */
    private boolean isValidElement(String element) {
        for (SpecificationKeyword keyword : SpecificationKeyword.class.getEnumConstants()) {
            if (element.startsWith(keyword.value + COLON)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get a named element defined in the specification.
     * 
     * @param elementName
     *            Name of the element to search
     * @param type
     *            Type of the element
     * @return Named element or null if does not exist in the current
     *         specification
     */
    @SuppressWarnings("rawtypes")
    private NamedElement getNamedElement(final String elementName, final Class type) {
        UnmodifiableIterator<EObject> it = Iterators.filter(specification.eAllContents(), new Predicate<EObject>() {
            public boolean apply(EObject eObject) {
                if (eObject != null && eObject instanceof NamedElement
                        && type.getSimpleName().equals(eObject.eClass().getName())) {
                    return elementName.equals(((NamedElement) eObject).getName());
                }
                return false;
            }
        });
        if (it.hasNext()) {
            return (NamedElement) it.next();
        }
        return null;
    }

    @Override
    public void init() {
        parsedElements.clear();
        specification = specificationFactory.createSpecification();
        specification.setName("UML Designer");
        automationLayer = specificationFactory.createAutomationLayer();
        automationLayer.setBasePackage("org.obeonetwork.dsl.uml2.design.tests");
        specification.setAutomationLayer(automationLayer);
    }

    @Override
    public void parsePostOperations(RepositoryAdapter repositoryAdapter) {
        for (ParsedElement parsedElement : parsedElements) {
            // Create a reference in the section if not exists
            ModelingUnitQuery query = new ModelingUnitQuery(repositoryAdapter);
            Collection<ExternalContentReference> externalContentReferences = query
                    .getAllExternalContentReferences();

            NamedElement namedElement = parsedElement.getNamedElement();
            Set<TestType> testTypes = SpecificationUtils.getTestTypes(namedElement);
            for (TestType testType : testTypes) {
                if (!TestType.MANUAL.equals(testType)) {
                    URI uri = SpecificationUtils.getTestURI(parsedElement.getNamedElement(), testType,
                            specification);
                    if (!referenceExists(externalContentReferences, uri)) {
                        createReference(parsedElement.getIntentSection(), uri);
                    }
                }
            }
        }

        // Serialize intent.specification
        resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("specification",
                new XMLResourceFactoryImpl());
        URI uri = URI.createURI(repositoryAdapter.getRepository().getRepositoryURI() + "/intent.specification");
        try {
            if (resource != null) {
                resource.delete(null);
            }
        } catch (IOException e) {
            SpecificationParserActivator.log(Status.ERROR, "The resource " + uri.devicePath() + "cannot be deleted",
                    e);
        }
        resource = resourceSet.createResource(uri);
        resource.getContents().add(specification);
        try {
            resource.save(null);
        } catch (IOException e) {
            SpecificationParserActivator.log(Status.ERROR, "The resource " + uri.devicePath() + "cannot be saved",
                    e);
        }
    }

    /**
     * Create a reference.
     * 
     * @param intentSection
     *            Intent section
     * @param uri
     *            URI of the file to reference
     */
    private void createReference(IntentSection intentSection, URI uri) {
        ModelingUnit modelingUnit = ModelingUnitFactory.eINSTANCE.createModelingUnit();
        ExternalContentReference referenceInstruction = ModelingUnitFactory.eINSTANCE
                .createExternalContentReference();
        referenceInstruction.setUri(uri);
        referenceInstruction.setMarkedAsMerged(true);

        modelingUnit.getInstructions().add(referenceInstruction);

        intentSection.getIntentContent().add(intentSection.getIntentContent().size(), modelingUnit);
    }

    /**
     * Check if a reference exists in the given reference list.
     * 
     * @param externalContentReferences
     *            Existing references
     * @param uri
     *            URI to check
     * @return True if reference exists in the given list otherwise false
     */
    private boolean referenceExists(final Collection<ExternalContentReference> externalContentReferences,
            final URI uri) {
        if (externalContentReferences.size() == 0) {
            return false;
        }
        for (ExternalContentReference externalContentReference : externalContentReferences) {
            if (uri.equals(externalContentReference.getUri())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<ExternalParserCompletionProposal> getCompletionVariablesProposals(
            final Iterable<String> currentSentences) {
        // Get last written sentence
        Iterator<String> iterator = currentSentences.iterator();
        String currentSentence = null;
        while (iterator.hasNext()) {
            currentSentence = (String) iterator.next();
        }

        List<ExternalParserCompletionProposal> variables = Lists.newArrayList();
        if ((currentSentence.contains(SpecificationKeyword.FEATURE.value)
                || currentSentence.contains(SpecificationKeyword.STORY.value))
                && currentSentence.contains(OPEN_BRACKET)) {
            // Feature: Name[Features] or Story: Name [Features]
            variables.addAll(getAllFeatures());
        } else if ((currentSentence.contains(SpecificationKeyword.SCENARIO.value))
                && currentSentence.contains(CLOSE_BRACKET)) {
            // Scenario: Name[Stories]@
            variables.addAll(getAllTestTypes());
        } else if ((currentSentence.contains(SpecificationKeyword.SCENARIO.value))
                && currentSentence.contains(OPEN_BRACKET)) {
            // Scenario: Name[Stories]
            variables.addAll(getAllStories());
        } else if (currentSentence.contains(SpecificationKeyword.AS.value)) {
            // As:
            variables.addAll(getAllRoles());
        } else if (currentSentence.contains(SpecificationKeyword.I_WANT.value)) {
            // I want:
            variables.addAll(getAllCapabilities());
        } else if (currentSentence.contains(SpecificationKeyword.SO_THAT.value)) {
            // So that:
            variables.addAll(getAllBenefits());
        } else if (currentSentence.contains(SpecificationKeyword.GIVEN.value)) {
            // Given:
            variables.addAll(getAllContexts());
        } else if (currentSentence.contains(SpecificationKeyword.WHEN.value)) {
            // When:
            variables.addAll(getAllActions());
        } else if (currentSentence.contains(SpecificationKeyword.THEN.value)) {
            // Then:
            variables.addAll(getAllBehaviours());
        }
        // Sorting proposals by alphabetical order
        Collections.sort(variables, new Comparator<ExternalParserCompletionProposal>() {

            @Override
            public int compare(final ExternalParserCompletionProposal o1,
                    final ExternalParserCompletionProposal o2) {
                return CommonPlugin.INSTANCE.getComparator().compare(o1.getName(), o2.getName());
            }
        });
        return variables;
    }

    /**
     * Get all the possible test types.
     * 
     * @return List of test types
     */
    private List<ExternalParserCompletionProposal> getAllTestTypes() {
        List<ExternalParserCompletionProposal> types = Lists.newArrayList();
        types.add(new ExternalParserCompletionProposal(AROBASE + TestType.UI.getName().toLowerCase(),
                "Define type of generated test", null,
                SpecificationParserActivator.getDefault().getImage("icon/specification/TestGenerationNote.gif")));
        types.add(new ExternalParserCompletionProposal(AROBASE + TestType.UNIT.getName().toLowerCase(),
                "Define type of generated test", null,
                SpecificationParserActivator.getDefault().getImage("icon/specification/TestGenerationNote.gif")));
        types.add(new ExternalParserCompletionProposal(AROBASE + TestType.PLUGIN.getName().toLowerCase(),
                "Define type of generated test", null,
                SpecificationParserActivator.getDefault().getImage("icon/specification/TestGenerationNote.gif")));
        types.add(new ExternalParserCompletionProposal(AROBASE + TestType.MANUAL.getName().toLowerCase(),
                "Define type of generated test", null,
                SpecificationParserActivator.getDefault().getImage("icon/specification/TestGenerationNote.gif")));
        return types;
    }

    /**
     * Get all roles defined in the specification.
     * 
     * @return All roles defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllRoles() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Role role : spec.getRoles()) {
            results.add(new ExternalParserCompletionProposal(role.getName(), Role.class.getSimpleName(), null,
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Role.gif")));
        }

        return results;
    }

    /**
     * Get all benefits defined in the specification.
     * 
     * @return All benefits defined in the specification or en empty list
     */
    private List<ExternalParserCompletionProposal> getAllBenefits() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Benefit benefit : spec.getBenefits()) {
            results.add(new ExternalParserCompletionProposal(benefit.getName(), Benefit.class.getSimpleName(), null,
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Benefit.gif")));
        }

        return results;
    }

    /**
     * Get all capabilities defined in the specification.
     * 
     * @return All capabilities defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllCapabilities() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Capability capability : spec.getCapabilities()) {
            results.add(new ExternalParserCompletionProposal(capability.getName(), Capability.class.getSimpleName(),
                    null, SpecificationParserActivator.getDefault().getImage("icon/specification/Capability.gif")));
        }

        return results;
    }

    /**
     * Get all contexts defined in the specification.
     * 
     * @return All contexts defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllContexts() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Context context : spec.getAutomationLayer().getContext()) {
            results.add(new ExternalParserCompletionProposal(context.getName(), Context.class.getSimpleName(), null,
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Context.gif")));
        }

        return results;
    }

    /**
     * Get all behaviours defined in the specification.
     * 
     * @return All behaviours defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllBehaviours() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Behaviour behaviour : spec.getAutomationLayer().getBehaviours()) {
            results.add(new ExternalParserCompletionProposal(behaviour.getName(), Behaviour.class.getSimpleName(),
                    null, SpecificationParserActivator.getDefault().getImage("icon/specification/Behaviour.gif")));
        }

        return results;
    }

    /**
     * Get all actions defined in the specification.
     * 
     * @return All actions defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllActions() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Action action : spec.getAutomationLayer().getActions()) {
            results.add(new ExternalParserCompletionProposal(action.getName(), Action.class.getSimpleName(), null,
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Action.gif")));
        }

        return results;
    }

    /**
     * Get all features defined in the specification.
     * 
     * @return All features defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllFeatures() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Feature feature : spec.getFeatures()) {
            results.add(new ExternalParserCompletionProposal(feature.getName(), Feature.class.getSimpleName(), null,
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Feature.gif")));
        }

        return results;
    }

    /**
     * Get all stories defined in the specification.
     * 
     * @return All stories defined in the specification or an empty list
     */
    private List<ExternalParserCompletionProposal> getAllStories() {
        Specification spec = (Specification) resource.getContents().get(0);
        List<ExternalParserCompletionProposal> results = Lists.newArrayList();
        for (Story story : spec.getStories()) {
            results.add(new ExternalParserCompletionProposal(story.getName(), Story.class.getSimpleName(), null,
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Story.gif")));
        }

        return results;
    }

    @Override
    public List<ExternalParserCompletionProposal> getCompletionTemplatesProposals(
            Iterable<String> currentSentences) {
        List<ExternalParserCompletionProposal> templates = Lists.newArrayList();
        Iterator<String> iterator = currentSentences.iterator();
        String currentSentence = null;
        while (iterator.hasNext()) {
            currentSentence = (String) iterator.next();
        }

        if (currentSentence.endsWith(SpecificationKeyword.FEATURE.value + COLON)) {
            // Feature:
            templates.add(new ExternalParserCompletionProposal("Feature", "Declare a new feature",
                    " ${Name} [${ParentFeature}]",
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Feature.gif")));
        } else if (currentSentence.endsWith(SpecificationKeyword.STORY.value + COLON)) {
            // Story:
            templates.add(new ExternalParserCompletionProposal("Story", "Declare a new story",
                    " ${Name} [${ReferencingFeature}]\n\tAs: ${Role}\n\tI want: ${Capability}\n\tSo that: ${Benefit}",
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Story.gif")));
        } else {
            // Add all the possible templates
            templates.add(new ExternalParserCompletionProposal("Feature", "Declare a new feature",
                    "Feature: ${Name} [${ParentFeature}]",
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Feature.gif")));
            templates.add(new ExternalParserCompletionProposal("Story", "Declare a new story",
                    "Story: ${Name} [${ReferencingFeature}]\n\tAs: ${Role}\n\tI want: ${Capability}\n\tSo that: ${Benefit}",
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Story.gif")));
            templates.add(new ExternalParserCompletionProposal("Scenario", "Declare a new scenario",
                    "Scenario: ${Name} [${ParentStory}]\n\tGiven: ${Context}\n\tWhen: ${Action}\n\tThen: ${Behaviour}",
                    SpecificationParserActivator.getDefault().getImage("icon/specification/Scenario.gif")));
        }
        return templates;
    }
}