metabest.transformations.MetaModel2Use.java Source code

Java tutorial

Introduction

Here is the source code for metabest.transformations.MetaModel2Use.java

Source

/*******************************************************************************
 * Copyright (c) 2015 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package metabest.transformations;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.xml.sax.SAXException;

import fragments.BooleanValue;
import fragments.Fragment;
import fragments.IntegerValue;
import fragments.PrimitiveValue;
import fragments.StringValue;
import test.ComplementaryBlock;
import test.ExtensionAssertion;
import test.ExtensionAssertionSet;
import test.FragmentObjectExtensionAssertion;
import test.MetaClassExtensionAssertion;
import test.TestableFragment;
import test.extensions.AndQualifier;
import test.extensions.AttributeValue;
import test.extensions.Contains;
import test.extensions.FragmentObjectQualifier;
import test.extensions.FragmentObjectSelector;
import test.extensions.MetaClassQualifier;
import test.extensions.MetaClassSelector;
import test.extensions.OrQualifier;
import test.extensions.Qualifier;
import test.extensions.Reach;
import test.extensions.Selector;
import metabup.annotations.IAnnotation;
import metabup.annotations.IAnnotationFactory;
import metabup.annotations.IConstraintAnnotation;
import metabup.annotations.catalog.design.Composition;
import metabup.metamodel.AnnotatedElement;
import metabup.metamodel.Annotation;
import metabup.metamodel.AnnotationParam;
import metabup.metamodel.Attribute;
import metabup.metamodel.ElementValue;
import metabup.metamodel.MetaClass;
import metabup.metamodel.MetaModel;
import metabup.metamodel.Reference;
import metabup.metamodel.impl.ReferenceImpl;
import metabup.sketches.Sketch;
import metabup.sketches.Sketch2Legend;
import metabup.sketches.XMLBasedImporter;
import metabup.sketches.importers.yed.YedImporter;
import metabup.sketches.legend.Legend;
import metabup.sketches.legend.LegendElement;
import metamodeltest.Every;
import metamodeltest.None;
import metamodeltest.Quantifier;

public class MetaModel2Use {
    private MetaModel mm = null;
    private File useFile = null;
    private HashMap<String, String> nameSwitch = new HashMap<String, String>();
    private IAnnotationFactory af = null;

    public static String DUMMY_CLASS_NAME = "DummyMetaBestClass";
    public static String DUMMY_OBJECT_NAME = "DummyMetaBestObject";

    public static String useWords[] = { "model", "constraints", "enum", "abstract", "class", "attributes",
            "operations", "end", "association", "composition", "aggregation", "between", "role", "ordered",
            "associationclass", "context", "inv", "pre", "post", "Set", "Bag", "Sequence", "Integer", "Real",
            "Boolean", "String", "from", "min", "max" };

    private List<Reference> serialized = new ArrayList<Reference>();

    public MetaModel2Use(MetaModel mm, IProject project, IAnnotationFactory factory, File legendFile) {
        this.mm = mm;
        this.af = factory;

        useFile = new File(project.getFile(mm.getName().substring(0, mm.getName().indexOf(".") - 1) + ".use")
                .getLocation().toString());

        if (useFile != null && useFile.exists()) {
            useFile.delete();
            try {
                useFile.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        nameSwitch = new HashMap<String, String>();
    }

    public HashMap<String, String> getNameSwitch() {
        return nameSwitch;
    }

    /*public void removeUseFile(){
       if(useFile != null && useFile.exists()){
     useFile.delete();
       }
    }*/

    public File execute(Fragment baseFragment, int minDefaultRefs, int maxDefaultRefs, boolean addAttributes,
            boolean addReferences, boolean addContainees, boolean makeUnreachable) throws IOException {
        if (mm == null || useFile == null)
            return null;

        FileWriter fw = new FileWriter(useFile.getAbsoluteFile());
        BufferedWriter bw = new BufferedWriter(fw);

        bw.write("model " + mm.getName().subSequence(0, mm.getName().indexOf(".")) + "\n");

        if (baseFragment != null)
            serializeDummyClass(bw);

        for (MetaClass mc : mm.getClasses())
            serializeClass(bw, mc);
        for (MetaClass mc : mm.getClasses())
            serializeClassReferences(bw, mc, ReferenceImpl.CONTAINMENT);
        for (MetaClass mc : mm.getClasses())
            serializeClassReferences(bw, mc, ReferenceImpl.ASSOCIATION);

        List<AnnotatedElement> elements = new ArrayList<AnnotatedElement>();
        elements.addAll(mm.getClasses());
        elements.addAll(mm.getReferences());
        serializeConstraints(bw, elements, baseFragment, minDefaultRefs, maxDefaultRefs, addAttributes,
                addReferences, addContainees, makeUnreachable);

        bw.close();

        return useFile;
    }

    private void serializeDummyClass(BufferedWriter bw) throws IOException {
        bw.write("\n\nclass " + this.DUMMY_CLASS_NAME + "\nend");
    }

    private void serializeConstraints(BufferedWriter bw, List<AnnotatedElement> aes, Fragment baseFragment,
            int minDefaultRefs, int maxDefaultRefs, boolean addAttributes, boolean addReferences,
            boolean addContainees, boolean makeUnreachable) throws IOException {

        bw.write("\n\nconstraints\n");

        // serialize class constraints
        for (AnnotatedElement ae : aes) {
            try {
                this.serializeElementConstraints(bw, ae);
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        // serialize default USE containment logics preventive constraints
        //serializeSelfReferenceConstraints(bw, mm.getClasses());
        serializeClassContainmentConstraints(bw, mm.getClasses());
        //serializeRefBoundsConstraints(bw, mm.getClasses(), minDefaultRefs, maxDefaultRefs);

        if (baseFragment != null) {
            //System.out.println("yo");
            serializeBaseFragmentConstraint(bw, baseFragment, addAttributes, addReferences, addContainees,
                    makeUnreachable);
        }

        //serializeGeometryConstraints(bw, mm.getClasses());

    }

    private void serializeSelfReferenceConstraints(BufferedWriter bw, EList<MetaClass> classes) throws IOException {
        if (classes == null || classes.isEmpty())
            return;

        for (MetaClass mc : classes) {
            if (mc.getReferences() == null || mc.getReferences().isEmpty())
                continue;
            String className = nameSwitch.get(mc.getName());

            for (Reference r : mc.getReferences()) {
                if (mc.equals(r.getReference()) || mc.isSuperTo(r.getReference())) {
                    String refName = nameSwitch.get(r.getName());
                    bw.write("\ncontext " + className + " inv " + className + "_" + refName + "_selfReference : ");
                    bw.write("\n\tnot self." + refName + " -> includes(self)");
                }
            }
        }
    }

    private void serializeRefBoundsConstraints(BufferedWriter bw, EList<MetaClass> classes, int min, int max)
            throws IOException {
        for (MetaClass mc : classes) {
            String className = nameSwitch.get(mc.getName());

            for (metabup.metamodel.Reference r : mc.getReferences()) {
                String refName = nameSwitch.get(r.getName());

                if (refName == null) {
                    refName = r.getName();
                    nameSwitch.put(r.getName(), r.getName());
                }

                int fixedMin = min, fixedMax = max;

                if (min < r.getMin())
                    fixedMin = r.getMin();
                if (r.getMax() != -1 && r.getMax() < max)
                    fixedMax = r.getMax();

                bw.write("\ncontext " + className + " inv " + className + "_" + refName + "_bounds : ");

                //context Coding inv bound : Coding.allInstances() -> forAll (c : Coding | c.nextPhase -> size() = 1)
                bw.write("\n\t" + className + ".allInstances() -> forAll (o : " + className + " | o." + refName
                        + " -> size() >= " + min);
                bw.write("\n\t\t and o." + refName + " -> size() <= " + max + ")");
            }
        }
    }

    private void serializeBaseFragmentConstraint(BufferedWriter bw, Fragment baseFragment, boolean addAttributes,
            boolean addReferences, boolean addContainees, boolean makeUnreachable) throws IOException {
        /*
         * NONE OF THIS IS NECESSARY ANYMORE (because of the change from line 401)
         * 
         * boolean someFeature = false;
            
        for(metabup.fragments.Object o : baseFragment.getObjects()){
           if(o.getFeatures() != null && !o.getFeatures().isEmpty()){
        someFeature = true;
        break;
           }
        }
            
        // IN CASE THE BASE FRAGMENT FEATURES MERELY CLASES (WITH NO FEATURES)
            
        if(!someFeature){         
           List<String> types = new ArrayList<String>();
               
           for(metabup.fragments.Object o : baseFragment.getObjects()){
        if(!types.contains(nameSwitch.get(o.getType()))){
           bw.write("\n\ncontext " + nameSwitch.get(o.getType()) + " inv BaseFragment_" + nameSwitch.get(o.getType()) + ":\n\t");
           bw.write(nameSwitch.get(o.getType()) + ".allInstances() -> size() >= " + baseFragment.getObjects(nameSwitch.get(o.getType())).size());
           types.add(nameSwitch.get(o.getType()));
        }
           }
           //return;
        }*/

        // IN CASE THE BASE FRAGMENT HAS FEATURES

        //bw.write("\n\ncontext " + this.DUMMY_CLASS_NAME + " inv DummyClassMinEvaluation : "+ this.DUMMY_CLASS_NAME + ".allInstances()->size() = 1\n");
        bw.write("\n\ncontext " + this.DUMMY_CLASS_NAME + " inv BaseFragment:\n\t");

        for (fragments.Object o : baseFragment.getObjects()) {
            bw.write(nameSwitch.get(o.getType()) + ".allInstances() -> exists(" + o.getName());
            //if(!baseFragment.getObjects().get(baseFragment.getObjects().size()-1).equals(o)) bw.write("|");
            bw.write(" | ");
            bw.write("\n\t");
        }

        boolean first = true;

        for (fragments.Object o : baseFragment.getObjects()) {
            for (fragments.Feature f : o.getFeatures()) {
                if (f instanceof fragments.Attribute) {
                    fragments.Attribute a = (fragments.Attribute) f;

                    if (first)
                        first = false;
                    else
                        bw.write(" and ");

                    bw.write("\n" + o.getName() + "." + nameSwitch.get(f.getName()) + " = ");

                    PrimitiveValue pv = a.getValues().get(0);

                    // only single multiplicity attributes for now

                    if (pv instanceof StringValue) {
                        /*StringValue sv = (StringValue)pv;
                        bw.write("\'" + sv.getValue() + "\'");*/
                    } else if (pv instanceof IntegerValue) {
                        IntegerValue iv = (IntegerValue) pv;
                        //System.out.println("here's your integer: " + iv.getValue());
                        bw.write(iv.getValue().toString());
                    } else if (pv instanceof BooleanValue) {
                        BooleanValue bv = (BooleanValue) pv;
                        bw.write(bv.getValue().toString());
                    }
                } else if (f instanceof fragments.Reference) {
                    fragments.Reference r = (fragments.Reference) f;
                    //System.out.println("yo");
                    //if(r.getReference().size() > 1){
                    if (first)
                        first = false;
                    else
                        bw.write(" and ");

                    bw.write("\n" + o.getName() + "." + nameSwitch.get(f.getName()));
                    bw.write(" -> includesAll(Set{");

                    for (fragments.Object to : r.getReference()) {
                        bw.write(to.getName());
                        if (!r.getReference().get(r.getReference().size() - 1).equals(to))
                            bw.write(", ");
                    }

                    bw.write("})");
                    /*}else{
                       if(first) first = false;
                       else bw.write(" and ");
                           
                       bw.write("\n" + o.getName() + "." + nameSwitch.get(f.getName()));
                       bw.write(" = " + r.getReference().get(0).getName());
                    }*/
                }
            }

            if (!addAttributes) {
                MetaClass mc = mm.getClassByName(nameSwitch.get(o.getType()));

                for (Attribute a : mc.getAttributes(true)) {
                    boolean found = false;

                    for (fragments.Feature of : o.getFeatures())
                        if (of.getName().equals(nameSwitch.get(a.getName())))
                            found = true;

                    /* if the object does not account certain feature and the user has selected not to augment
                     * objects with undefined attributes, then USE is forbidden to do so */
                    if (!found) {
                        if (first)
                            first = false;
                        else
                            bw.write(" and ");

                        bw.write("\n" + o.getName() + "." + nameSwitch.get(a.getName()) + " -> oclIsUndefined()");
                    } else {
                        // if cardinality is to be considered with attributes... 
                    }
                }
            }

            if (!addReferences) {
                MetaClass mc = mm.getClassByName(nameSwitch.get(o.getType()));

                for (Reference r : mc.getReferences(true, ReferenceImpl.ASSOCIATION)) {
                    boolean found = false;
                    fragments.Reference thisOne = null;

                    for (fragments.Feature of : o.getFeatures()) {
                        if (of instanceof fragments.Reference && of.getName().equals(nameSwitch.get(r.getName()))) {
                            found = true;
                            thisOne = (fragments.Reference) of;
                        }
                    }

                    /* if the object does not account certain feature and the user has selected not to augment
                     * objects with undefined references, then USE is forbidden to do so */
                    if (!found) {
                        if (first)
                            first = false;
                        else
                            bw.write(" and ");

                        bw.write("\n" + o.getName() + "." + nameSwitch.get(r.getName()) + " -> oclIsUndefined()");
                    } else {
                        if (first)
                            first = false;
                        else
                            bw.write(" and ");

                        bw.write("\n" + o.getName() + "." + nameSwitch.get(r.getName()) + " -> size() = "
                                + thisOne.getReference().size());
                    }
                }
            }

            if (!addContainees) {
                MetaClass mc = mm.getClassByName(nameSwitch.get(o.getType()));

                for (Reference r : mc.getReferences(true, ReferenceImpl.CONTAINMENT)) {
                    boolean found = false;
                    fragments.Reference thisOne = null;

                    for (fragments.Feature of : o.getFeatures()) {
                        if (of instanceof fragments.Reference && of.getName().equals(nameSwitch.get(r.getName()))) {
                            found = true;
                            thisOne = (fragments.Reference) of;
                        }
                    }

                    if (!found) {
                        if (first)
                            first = false;
                        else
                            bw.write(" and ");

                        bw.write("\n" + o.getName() + "." + nameSwitch.get(r.getName()) + " -> oclIsUndefined()");
                    } else {
                        if (first)
                            first = false;
                        else
                            bw.write(" and ");

                        bw.write("\n" + o.getName() + "." + nameSwitch.get(r.getName()) + " -> size() = "
                                + thisOne.getReference().size());
                    }
                }
            }
        }

        /*
         * if the user doesn't wish the base fragment to be reached by new objects, then we armour them
        */
        if (makeUnreachable) {
            List<metabup.metamodel.Reference> refs = new ArrayList<metabup.metamodel.Reference>();

            int i = 0;

            jump: for (metabup.metamodel.Reference r : mm.getReferences()) {
                String srcclass = nameSwitch.get(((MetaClass) r.eContainer()).getName());
                String tarclass = nameSwitch.get(r.getReference().getName());

                List<MetaClass> tarSubs = r.getReference().getAllSubs();
                List<fragments.Object> tarObs = new ArrayList<fragments.Object>();
                tarObs.addAll(baseFragment.getObjects(tarclass));

                for (MetaClass sub : tarSubs)
                    tarObs.addAll(baseFragment.getObjects(nameSwitch.get(sub.getName())));

                if (tarObs.isEmpty())
                    continue jump;

                List<MetaClass> srcSubs = mm.getClassByName(srcclass).getAllSubs();
                List<fragments.Object> srcObs = new ArrayList<fragments.Object>();
                srcObs.addAll(baseFragment.getObjects(srcclass));

                for (MetaClass sub : srcSubs)
                    srcObs.addAll(baseFragment.getObjects(nameSwitch.get(sub.getName())));

                if (first)
                    first = false;
                else
                    bw.write(" and ");

                bw.write("\n" + srcclass + ".allInstances() -> excludesAll( " + srcclass
                        + ".allInstances() -> select (" + this.DUMMY_OBJECT_NAME + i + " | ");

                boolean thisFirst = true;

                for (fragments.Object o : srcObs) {
                    if (thisFirst)
                        thisFirst = false;
                    else
                        bw.write(" and ");
                    bw.write("\n\t\t" + this.DUMMY_OBJECT_NAME + i + " <> " + o.getName() + " ");
                }

                boolean oneMoreBracket = false;

                if (thisFirst)
                    thisFirst = false;
                else {
                    bw.write(" and (");
                    oneMoreBracket = true;
                }

                boolean orFirst = true;

                for (fragments.Object o : tarObs) {
                    if (orFirst)
                        orFirst = false;
                    else
                        bw.write(" or ");
                    bw.write("\n\t\t\t" + this.DUMMY_OBJECT_NAME + i + "."
                            + nameSwitch.get(nameSwitch.get(r.getName())) + "->includes(" + o.getName() + ")");
                }

                bw.write("))");

                if (oneMoreBracket)
                    bw.write(")");

                i++;
            }
        }

        if (baseFragment.getObjects().size() > 1) {
            for (fragments.Object o1 : baseFragment.getObjects()) {
                for (fragments.Object o2 : baseFragment.getObjects()) {
                    if (!o1.equals(o2) && o1.getType().equals(o2.getType())) {
                        if (first)
                            first = false;
                        else
                            bw.write(" and ");

                        bw.write("\n" + o1.getName() + " <> " + o2.getName());
                    }
                }
            }
        }

        //System.out.println("CLASS: " + baseFragment.getClass());
        if (baseFragment instanceof TestableFragment) {
            TestableFragment tf = (TestableFragment) baseFragment;
            ComplementaryBlock cb = tf.getAssertionSet();
            System.out.println("yo again");
            // in case there are extension conditions
            if (cb != null && cb instanceof ExtensionAssertionSet) {
                ExtensionAssertionSet eas = (ExtensionAssertionSet) cb;
                for (ExtensionAssertion ea : eas.getAssertions()) {
                    if (first)
                        first = false;
                    else
                        bw.write(" and ");
                    serializeExtensionAssertion(bw, ea, baseFragment);
                }
            }

            bw.write("\n");
        }

        if (first)
            bw.write("true");

        for (fragments.Object o : baseFragment.getObjects())
            bw.write(")");
    }

    private void serializeExtensionAssertion(BufferedWriter bw, ExtensionAssertion ea, Fragment baseFragment)
            throws IOException {
        // assertion 'bout a metaclass
        if (ea instanceof MetaClassExtensionAssertion)
            serializeMetaClassExtensionAssertion(bw, (MetaClassExtensionAssertion) ea, baseFragment);
        else if (ea instanceof FragmentObjectExtensionAssertion)
            serializeFragmentObjectExtensionAssertion(bw, (FragmentObjectExtensionAssertion) ea, baseFragment);
    }

    private void serializeMetaClassExtensionAssertion(BufferedWriter bw, MetaClassExtensionAssertion ea,
            Fragment baseFragment) throws IOException {
        MetaClassSelector selector = ((MetaClassExtensionAssertion) ea).getSelector();
        String className = selector.getMetaclassName();
        boolean onlyNewElements = selector.isOnlyNewElements();
        MetaClass metaclass = mm.getClassByName(className);

        if (metaclass == null) {
            // Class not found. Report error
            return;
        }

        bw.write("\n" + className + ".allInstances() ");

        if (onlyNewElements) {
            List<MetaClass> subs = metaclass.getAllSubs();
            //System.out.println("HERE: " + subs.size());
            List<String> subNames = new ArrayList<String>();
            for (MetaClass mc : subs)
                subNames.add(mc.getName());
            subNames.add(metaclass.getName());

            for (String classname : subNames)
                for (fragments.Object o : baseFragment.getObjects(classname))
                    bw.write(" -> excluding(" + o.getName() + ")");
        }

        serializeMetaClassExtensionAssertionFilter(true, bw, mm.getClassByName(className), selector.getFilter(),
                baseFragment);

        Quantifier q = selector.getQuantifier();

        if (q instanceof Every) {
            bw.write(" -> size()");

            if (!((Every) q).isNot())
                bw.write(" = ");
            else
                bw.write(" > ");

            bw.write(className + ".allInstances() ");

            if (onlyNewElements) {
                List<MetaClass> subs = metaclass.getAllSubs();
                //System.out.println("HERE: " + subs.size());
                List<String> subNames = new ArrayList<String>();
                for (MetaClass mc : subs)
                    subNames.add(mc.getName());
                subNames.add(metaclass.getName());

                for (String classname : subNames)
                    for (fragments.Object o : baseFragment.getObjects(classname))
                        bw.write(" -> excluding(" + o.getName() + ")");
            }

            serializeMetaClassExtensionAssertionFilter(true, bw, mm.getClassByName(className), selector.getFilter(),
                    baseFragment);
            serializeMetaClassExtensionAssertionFilter(true, bw, mm.getClassByName(className),
                    ((MetaClassExtensionAssertion) ea).getCondition(), baseFragment);

            bw.write(" -> size()");
        } else {
            int minmax[] = q.getQuantity(Integer.MAX_VALUE);

            int min = minmax[0];
            int max = minmax[1];

            serializeMetaClassExtensionAssertionFilter(true, bw, mm.getClassByName(className),
                    ((MetaClassExtensionAssertion) ea).getCondition(), baseFragment);

            if (min == max)
                bw.write(" -> size() = " + min);
            else {
                bw.write("-> size() >= " + min);
                if (max < Integer.MAX_VALUE)
                    bw.write(" and size() <= " + max);
            }
        }
    }

    private void serializeFragmentObjectExtensionAssertion(BufferedWriter bw, FragmentObjectExtensionAssertion ea,
            Fragment baseFragment) throws IOException {
        FragmentObjectSelector fos = ((FragmentObjectExtensionAssertion) ea).getSelector();
        String className = fos.getObject().getType();

        if (mm.getClassByName(className) == null) {
            // Class not found. Report error
            return;
        }

        bw.write("\n");
        serializeFragmentObjectExtensionAssertionFilter(bw, fos.getObject(),
                ((FragmentObjectExtensionAssertion) ea).getCondition(), baseFragment);
    }

    private void serializeFragmentObjectExtensionAssertionFilter(BufferedWriter bw, fragments.Object object,
            FragmentObjectQualifier filter, Fragment baseFragment) throws IOException {
        MetaClass metaclass = mm.getClassByName(object.getType());

        if (filter instanceof AndQualifier) {
            boolean firstAnd = true;

            bw.write("(");

            for (Qualifier mcq : ((AndQualifier) filter).getQualifiers()) {
                if (firstAnd)
                    firstAnd = false;
                else
                    bw.write(" and ");
                serializeFragmentObjectExtensionAssertionFilter(bw, object, (FragmentObjectQualifier) mcq,
                        baseFragment);
            }

            bw.write(")");

            return;
        }

        if (filter instanceof OrQualifier) {
            boolean firstOr = true;

            bw.write("(");

            for (Qualifier mcq : ((OrQualifier) filter).getQualifiers()) {
                if (firstOr)
                    firstOr = false;
                else
                    bw.write(" or ");
                serializeFragmentObjectExtensionAssertionFilter(bw, object, (FragmentObjectQualifier) mcq,
                        baseFragment);
            }

            bw.write(")");

            return;
        }

        if (filter instanceof AttributeValue) {
            AttributeValue av = (AttributeValue) filter;

            if (metaclass.getAttributes() == null) {
                // Attribute not found. Report error
                return;
            }

            bw.write(object.getName() + "." + av.getAttributeName() + " = " + av.getValueAsString());

            return;
        }

        if (filter instanceof Reach) {
            Reach reach = (Reach) filter;
            Selector sel = reach.getReachSelector();

            if (sel instanceof MetaClassSelector) {
                MetaClassSelector mcs = (MetaClassSelector) sel;

                boolean onlyNewElements = mcs.isOnlyNewElements();
                String tgtclassName = mcs.getMetaclassName();

                if (mm.getClassByName(tgtclassName) == null) {
                    // Class not found. Report error
                    return;
                }

                Quantifier q = mcs.getQuantifier();
                int minmax[] = q.getQuantity(Integer.MAX_VALUE);

                int min = minmax[0];
                int max = minmax[1];

                // find the reference(s) which point to the target metaclass(es)
                List<Reference> refs = new ArrayList<Reference>();

                int refSort = ReferenceImpl.IRRELEVANT;
                if (filter instanceof Contains)
                    refSort = ReferenceImpl.CONTAINMENT;

                if (((Reach) filter).getRefName() == null) {
                    for (Reference r : metaclass.getReferences(true, refSort))
                        if (r.getReference().getName().equals(tgtclassName))
                            refs.add(r);
                } else
                    refs.add(metaclass.getReferenceByName(((Reach) filter).getRefName(), true));

                if (refs.isEmpty()) {
                    // reference not found 
                    return;
                }

                // no more filters
                if (mcs.getFilter() == null) {
                    boolean firstOr = true;

                    bw.write("(");

                    for (Reference r : refs) {
                        if (firstOr)
                            firstOr = false;
                        else
                            bw.write(" or ");

                        bw.write(object.getName() + "." + r.getName() + "-> asSet()");

                        if (onlyNewElements) {
                            for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                bw.write(" -> excluding(" + o.getName() + ")");

                            MetaClass tarClass = ((MetaModel) metaclass.eContainer()).getClassByName(tgtclassName);
                            List<MetaClass> subs = tarClass.getAllSubs();
                            List<String> subNames = new ArrayList<String>();
                            for (MetaClass mc : subs)
                                subNames.add(mc.getName());

                            for (String classname : subNames)
                                for (fragments.Object o : baseFragment.getObjects(classname))
                                    bw.write(" -> excluding(" + o.getName() + ")");
                        }

                        if (min == max)
                            bw.write("-> size() = " + min);
                        else {
                            bw.write("-> size() >= " + min);

                            if (max < Integer.MAX_VALUE) {
                                bw.write(" and " + r.getName() + "-> asSet()");

                                if (onlyNewElements) {
                                    for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                        bw.write(" -> excluding(" + o.getName() + ")");

                                    MetaClass tarClass = ((MetaModel) metaclass.eContainer())
                                            .getClassByName(tgtclassName);
                                    List<MetaClass> subs = tarClass.getAllSubs();
                                    List<String> subNames = new ArrayList<String>();
                                    for (MetaClass mc : subs)
                                        subNames.add(mc.getName());

                                    for (String classname : subNames)
                                        for (fragments.Object o : baseFragment.getObjects(classname))
                                            bw.write(" -> excluding(" + o.getName() + ")");
                                }

                                bw.write(" -> size() <= " + max);
                            }
                        }
                    }

                    bw.write(")");
                } else {
                    boolean firstOr = true;

                    bw.write("(");

                    for (Reference r : refs) {
                        if (firstOr)
                            firstOr = false;
                        else
                            bw.write(" or ");

                        bw.write(object.getName() + "." + r.getName() + " -> asSet()");

                        if (onlyNewElements) {
                            for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                bw.write(" -> excluding(" + o.getName() + ")");

                            MetaClass tarClass = ((MetaModel) metaclass.eContainer()).getClassByName(tgtclassName);
                            List<MetaClass> subs = tarClass.getAllSubs();
                            List<String> subNames = new ArrayList<String>();
                            for (MetaClass mc : subs)
                                subNames.add(mc.getName());

                            for (String classname : subNames)
                                for (fragments.Object o : baseFragment.getObjects(classname))
                                    bw.write(" -> excluding(" + o.getName() + ")");
                        }

                        serializeMetaClassExtensionAssertionFilter(true, bw, mm.getClassByName(tgtclassName),
                                mcs.getFilter(), baseFragment);

                        if (min == max)
                            bw.write("-> size() = " + min);
                        else {
                            bw.write("-> size() >= " + min);

                            if (max < Integer.MAX_VALUE) {
                                bw.write(" and " + r.getName() + " -> asSet()");

                                if (onlyNewElements) {
                                    for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                        bw.write(" -> excluding(" + o.getName() + ")");
                                }

                                bw.write(" -> size() <= " + max);
                            }
                        }
                    }

                    bw.write(")");
                }
            }

            if (sel instanceof FragmentObjectSelector) {
                FragmentObjectSelector fos = (FragmentObjectSelector) sel;
                //bw.write(" -> select(" + fos.getObject().getName() + ")");

                List<Reference> refs = new ArrayList<Reference>();
                int refSort = ReferenceImpl.IRRELEVANT;
                if (filter instanceof Contains)
                    refSort = ReferenceImpl.CONTAINMENT;

                if (((Reach) filter).getRefName() == null) {
                    for (Reference r : metaclass.getReferences(true, refSort)) {
                        MetaClass tarClass = ((MetaModel) metaclass.eContainer())
                                .getClassByName(r.getReference().getName());
                        List<MetaClass> subs = tarClass.getAllSubs();
                        List<String> subNames = new ArrayList<String>();
                        for (MetaClass mc : subs)
                            subNames.add(mc.getName());
                        if (r.getReference().getName().equals(fos.getObject().getType())
                                || subNames.contains(fos.getObject().getType()))
                            refs.add(r);
                    }
                } else
                    refs.add(metaclass.getReferenceByName(((Reach) filter).getRefName(), true));

                if (refs.isEmpty()) {
                    // reference not found 
                    return;
                }

                //System.out.println("... and I get here");

                boolean firstOr = true;

                bw.write("(");

                for (Reference r : refs) {
                    if (firstOr)
                        firstOr = false;
                    else
                        bw.write(" or ");

                    bw.write(object.getName() + "." + r.getName() + "-> asSet()");
                    bw.write(" -> includes(" + fos.getObject().getName() + ")");
                }

                bw.write(")");
            }
        }

    }

    private void serializeMetaClassExtensionAssertionFilter(boolean start, BufferedWriter bw, MetaClass metaclass,
            MetaClassQualifier filter, Fragment baseFragment) throws IOException {
        if (filter instanceof AndQualifier) {
            for (Qualifier mcq : ((AndQualifier) filter).getQualifiers())
                serializeMetaClassExtensionAssertionFilter(true, bw, metaclass, (MetaClassQualifier) mcq,
                        baseFragment);
            return;
        }

        if (filter instanceof OrQualifier) {
            bw.write(" -> select(");
            boolean firstOr = true;

            for (Qualifier mcq : ((OrQualifier) filter).getQualifiers()) {

                if (firstOr)
                    firstOr = false;
                else
                    bw.write(" or ");

                serializeMetaClassExtensionAssertionFilter(false, bw, metaclass, (MetaClassQualifier) mcq,
                        baseFragment);
            }

            bw.write(")");
            return;
        }

        if (filter instanceof AttributeValue) {
            AttributeValue av = (AttributeValue) filter;

            if (metaclass.getAttributes() == null) {
                // Attribute not found. Report error
                return;
            }

            /*if(av.getBooleanValue() != null){
               if(av.getBooleanValue().equals("true")) bw.write("-> select(" + av.getAttributeName() + ") ");
               else bw.write("-> select(not " + av.getAttributeName() + ") ");
            }else*/

            if (start)
                bw.write("-> select(");
            bw.write(av.getAttributeName() + " = " + av.getValueAsString());
            if (start)
                bw.write(") ");

            return;
        }

        if (filter instanceof Reach) {
            Reach reach = (Reach) filter;
            Selector sel = reach.getReachSelector();

            if (sel instanceof MetaClassSelector) {
                MetaClassSelector mcs = (MetaClassSelector) sel;

                boolean onlyNewElements = mcs.isOnlyNewElements();
                String tgtclassName = mcs.getMetaclassName();

                if (mm.getClassByName(tgtclassName) == null) {
                    // Class not found. Report error
                    return;
                }

                Quantifier q = mcs.getQuantifier();
                int minmax[] = q.getQuantity(Integer.MAX_VALUE);

                int min = minmax[0];
                int max = minmax[1];

                // find the reference(s) which point to the target metaclass(es)
                List<Reference> refs = new ArrayList<Reference>();

                int refSort = ReferenceImpl.IRRELEVANT;
                if (filter instanceof Contains)
                    refSort = ReferenceImpl.CONTAINMENT;

                if (((Reach) filter).getRefName() == null) {
                    for (Reference r : metaclass.getReferences(true, refSort)) {
                        MetaClass tarClass = ((MetaModel) metaclass.eContainer())
                                .getClassByName(r.getReference().getName());
                        List<MetaClass> subs = tarClass.getAllSubs();
                        List<String> subNames = new ArrayList<String>();
                        for (MetaClass mc : subs)
                            subNames.add(mc.getName());
                        if (r.getReference().getName().equals(tgtclassName) || subNames.contains(tgtclassName))
                            refs.add(r);
                    }
                } else
                    refs.add(metaclass.getReferenceByName(((Reach) filter).getRefName(), true));

                if (refs.isEmpty()) {
                    // reference not found 
                    return;
                }

                // no more filters
                if (mcs.getFilter() == null) {
                    if (start)
                        bw.write("-> select(");

                    boolean firstOr = true;

                    for (Reference r : refs) {
                        if (firstOr)
                            firstOr = false;
                        else
                            bw.write(" -> union ");

                        bw.write("(" + r.getName() + "-> asSet() ");

                        if (onlyNewElements) {
                            for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                bw.write(" -> excluding(" + o.getName() + ")");
                        }

                        bw.write(")");
                    }

                    bw.write(" -> select(oclIsKindOf(" + tgtclassName + "))");
                    if (min == max)
                        bw.write("-> size() = " + min);
                    else {
                        bw.write("-> size() >= " + min);

                        if (max < Integer.MAX_VALUE) {
                            bw.write(" and ");

                            for (Reference r : refs) {
                                if (firstOr)
                                    firstOr = false;
                                else
                                    bw.write(" -> union ");

                                bw.write("(" + r.getName() + "-> asSet() ");

                                if (onlyNewElements) {
                                    for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                        bw.write(" -> excluding(" + o.getName() + ")");
                                }

                                bw.write(")");
                            }

                            bw.write(" -> select(oclIsKindOf(" + tgtclassName + "))");
                            bw.write(" -> size() <= " + max);
                        }
                    }

                    if (start)
                        bw.write(") ");
                } else {
                    if (start)
                        bw.write("-> select(");

                    boolean firstOr = true;

                    for (Reference r : refs) {
                        if (firstOr)
                            firstOr = false;
                        else
                            bw.write(" or ");

                        bw.write("(" + r.getName() + " -> asSet()");

                        if (onlyNewElements) {
                            for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                bw.write(" -> excluding(" + o.getName() + ")");
                        }

                        serializeMetaClassExtensionAssertionFilter(true, bw, mm.getClassByName(tgtclassName),
                                mcs.getFilter(), baseFragment);

                        if (min == max)
                            bw.write("-> size() = " + min);
                        else {
                            bw.write("-> size() >= " + min);

                            if (max < Integer.MAX_VALUE) {
                                bw.write(" and " + r.getName() + " -> asSet()");

                                if (onlyNewElements) {
                                    for (fragments.Object o : baseFragment.getObjects(tgtclassName))
                                        bw.write(" -> excluding(" + o.getName() + ")");
                                }

                                bw.write(" -> size() <= " + max);
                            }
                        }

                        bw.write(")");
                    }

                    if (start)
                        bw.write(") ");
                }
            }

            if (sel instanceof FragmentObjectSelector) {
                System.out.println("be here");
                FragmentObjectSelector fos = (FragmentObjectSelector) sel;
                //bw.write(" -> select(" + fos.getObject().getName() + ")");

                List<Reference> refs = new ArrayList<Reference>();
                int refSort = ReferenceImpl.IRRELEVANT;
                if (filter instanceof Contains)
                    refSort = ReferenceImpl.CONTAINMENT;

                if (((Reach) filter).getRefName() == null) {
                    for (Reference r : metaclass.getReferences(true, refSort)) {
                        if (r.getReference().getName().equals(fos.getObject().getType()))
                            refs.add(r);
                        else {
                            MetaClass tarClass = ((MetaModel) metaclass.eContainer())
                                    .getClassByName(r.getReference().getName());
                            List<MetaClass> subs = tarClass.getAllSubs();
                            List<String> subNames = new ArrayList<String>();
                            for (MetaClass mc : subs)
                                subNames.add(mc.getName());
                            if (subNames.contains(fos.getObject().getType()))
                                refs.add(r);
                        }
                    }
                } else
                    refs.add(metaclass.getReferenceByName(((Reach) filter).getRefName(), true));

                if (refs.isEmpty()) {
                    // reference not found 
                    return;
                }

                if (start)
                    bw.write("-> select(");

                boolean firstOr = true;

                for (Reference r : refs) {
                    if (firstOr)
                        firstOr = false;
                    else
                        bw.write(" -> union ");

                    bw.write("(" + r.getName() + "-> asSet())");
                }

                if (start)
                    bw.write(") ");
                bw.write(" -> select(o | o =" + fos.getObject().getName() + ")");
            }
        }
    }

    private void serializeClassContainmentConstraints(BufferedWriter bw, List<MetaClass> mcs) throws IOException {
        for (MetaClass mc : mcs)
            for (Reference r : mc.getReferences(false, ReferenceImpl.CONTAINMENT))
                bw.write(selfCompositionConstraint(r));

        List<Reference> conts = new ArrayList<Reference>();
        for (MetaClass mc : mcs)
            for (Reference r : mc.getReferences(false, ReferenceImpl.CONTAINMENT))
                conts.add(r);
        System.out.println("here!!! " + conts.size());
        bw.write(simultaneousCompositionConstraint(conts));
    }

    // constraint: an object cannot be contained itself through a composition relation, directly or indirectly
    // [NOTE: we do this because the USE Validator does not take into account the semantics of composition] 
    private String selfCompositionConstraint(Reference ref) {
        String constraint = "";
        MetaClass container = (MetaClass) ref.eContainer();
        MetaClass containee = ref.getReference();
        if (ref != null && ref.isAnnotated(Composition.NAME)
                && (container.equals(containee) || container.getSupers().contains(containee))) {
            List<String> terms = new ArrayList<String>();
            int num_terms = 4;
            String type = container.getName();
            String setOpen = ref.getMax() == 1 ? "Set{" : ""; // add monovalued features to a set
            String setClose = ref.getMax() == 1 ? "}" : "";

            for (int term = 1; term <= num_terms; term++) {
                String expression = "";
                for (int index = 1; index <= term; index++) {
                    if (index == 1) {
                        expression = setOpen + (index < term ? ref.getName() + index : "self") + ".oclAsType("
                                + type + ")." + ref.getName() + setClose + "->includes(self)";
                    } else {
                        String select1 = "", select2 = "";
                        if (index > 1) {
                            select1 = setOpen + (index < term ? ref.getName() + index : "self") + ".oclAsType("
                                    + type + ")." + ref.getName() + setClose + "->exists(" + ref.getName()
                                    + (index - 1) + " |\n";
                            select2 = ")";
                        }
                        expression = select1 + "if " + ref.getName() + (index - 1) + ".oclIsTypeOf(" + type
                                + ") then\n" + "\t" + expression + "\n" + "\t else false endif" + select2;
                    }
                }
                terms.add("not " + expression);
            }

            constraint = "\n\ncontext " + container.getName() + " inv non_contains_itself_" + ref.getName() + ":\n";
            for (String term : terms)
                constraint += term + "\nand\n";
            constraint = constraint.substring(0, constraint.lastIndexOf("and")) + "\n";
        }

        return constraint;
    }

    // constraint: an object cannot be contained in two containers
    // [NOTE: we do this because the USE Validator does not take into account the semantics of composition] 
    private String simultaneousCompositionConstraint(List<Reference> references) {
        String constraints = "";

        // obtain the containment references that can contain each class
        Hashtable<String, List<Reference>> containers = new Hashtable<String, List<Reference>>();

        for (Reference ref : references) {
            if (ref.isAnnotated(Composition.NAME)) {
                String classname = ref.getReference().getName();
                if (!containers.containsKey(classname))
                    containers.put(classname, new ArrayList<Reference>());
                containers.get(classname).add(ref);
            }
            if (ref.getOpposite() != null && ref.getOpposite().isAnnotated(Composition.NAME)) {
                String classname = ref.getOpposite().getReference().getName();
                if (!containers.containsKey(classname))
                    containers.put(classname, new ArrayList<Reference>());
                containers.get(classname).add(ref.getOpposite());
            }
        }

        // if a class can potentially be in more than two containers, add a constraint
        for (Entry<String, List<Reference>> entry : containers.entrySet()) {
            if (entry.getValue().size() > 1) {
                constraints += "\n\ncontext " + entry.getKey() + "\n\tinv single_container: ";
                constraints += "\n";
                for (Reference ref : entry.getValue())
                    constraints += "\t" + ((MetaClass) ref.eContainer()).getName()
                            + ".allInstances()->collect(o | o." + ref.getName() + ")->count(self) +\n";
                constraints = constraints.substring(0, constraints.lastIndexOf("+")) + "<= 1";
            }
        }
        if (!constraints.isEmpty())
            constraints += "\n";

        return constraints;
    }

    private void serializeClass(BufferedWriter bw, MetaClass mc) throws IOException {
        bw.write("\n\n");
        if (mc.getIsAbstract())
            bw.write("abstract ");
        bw.write("class ");
        bw.write(getNameSwitch(mc.getName()));

        if (mc.getSupers() != null && !mc.getSupers().isEmpty()) {
            bw.write(" < ");

            for (int i = 0; i < mc.getSupers().size(); i++) {
                bw.write(getNameSwitch(mc.getSupers().get(i).getName()));
                if (i < mc.getSupers().size() - 1)
                    bw.write(" , ");
            }
        }

        serializeClassAttributes(bw, mc);

        /*if(mc.getAnnotations() != null && !mc.getAnnotations().isEmpty()){
           try {
        serializeElementConstraints(bw, mc);
           } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
           } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
           }
        }*/

        bw.write("\nend");
    }

    private void serializeElementConstraints(BufferedWriter bw, AnnotatedElement ae)
            throws IOException, InstantiationException, IllegalAccessException {
        for (Annotation a : ae.getAnnotations()) {
            Class<? extends IConstraintAnnotation> annotationClass = af.getConstraintAnnotation(a.getName());

            if (annotationClass != null) {
                System.out.println("annotation to serialize: " + a.getName());
                IConstraintAnnotation annotation = annotationClass.newInstance();
                annotation.setElement(ae);
                Iterator it = annotation.getConstraints().entrySet().iterator();

                while (it.hasNext()) {
                    Map.Entry e = (Map.Entry) it.next();
                    //if(!constraint.startsWith("context")) constraint = "context " + mc.getName() + " " + constraint;
                    bw.write("\n\n");
                    bw.write(e.getValue().toString());
                    System.out.println(e.getValue().toString());
                }
            }
        }
    }

    private void serializeClassAttributes(BufferedWriter bw, MetaClass mc) throws IOException {
        if (!mc.getAttributes().isEmpty())
            bw.write("\n\tattributes");
        List<String> atts = new ArrayList<String>();

        for (Attribute a : mc.getAttributes()) {
            if (!atts.contains(a.getName())) { // repeated attributes are removed
                bw.write("\n\t\t" + getNameSwitch(a.getName()));
                bw.write(" : ");
                if (a.getPrimitiveType().equals("StringType"))
                    bw.write("String");
                else if (a.getPrimitiveType().equals("IntType"))
                    bw.write("Integer");
                else if (a.getPrimitiveType().equals("BooleanType"))
                    bw.write("Boolean");
                else
                    bw.write("String");

                atts.add(a.getName());
            }
        }
    }

    private void serializeClassReferences(BufferedWriter bw, MetaClass mc, int refSort) throws IOException {
        List<Reference> refs = mc.getReferences(false, refSort);

        for (Reference r : refs) {
            System.out.println(serialized);
            if (serialized.contains(r))
                continue;

            //System.out.println(r.getName() + " annotated: " + r.getAnnotations());
            if (r.isAnnotated(Composition.NAME))
                bw.write("\n\ncomposition ");
            else
                bw.write("\n\nassociation ");

            String name = mc.getName() + "_" + r.getName();

            Reference opp = null;

            if (r.isAnnotated("opposite")) {
                for (Annotation a : r.getAnnotations())
                    if (a.getName().equals("opposite"))
                        for (AnnotationParam ap : a.getParams())
                            if (ap.getName().equals("opp")) {
                                ElementValue ev = (ElementValue) ap.getValue();
                                opp = (Reference) ev.getValue();
                                break;
                            }
            }

            //System.out.println("here");

            if (opp != null)
                name += "_" + opp.getName();
            bw.write(getNameSwitch(name));
            bw.write(" between");
            bw.write("\n\t" + getNameSwitch(mc.getName()) + "[");

            if (opp != null) {
                bw.write(Integer.toString(opp.getMin()) + "..");
                if (opp.getMax() < 0)
                    bw.write("*");
                else
                    bw.write(Integer.toString(opp.getMax()));
            } else
                bw.write("1..1");

            bw.write("]");

            if (opp != null)
                bw.write(" role " + getNameSwitch(opp.getName()));
            else
                bw.write(" role " + getNameSwitch(mc.getName()).toLowerCase() + "_" + getNameSwitch(r.getName()));

            bw.write(
                    "\n\t" + getNameSwitch(r.getReference().getName()) + "[" + Integer.toString(r.getMin()) + "..");

            if (r.getMax() < 0)
                bw.write("*");
            else
                bw.write(Integer.toString(r.getMax()));

            bw.write("]" + " role " + getNameSwitch(r.getName()));
            bw.write("\nend");

            serialized.add(r);
            if (opp != null)
                serialized.add(opp);
        }
    }

    private String getNameSwitch(String name) {
        if (isReserved(name)) {
            String fixedName = name + "_RESERVEDWORD";
            nameSwitch.put(name, fixedName);
            return fixedName;
        }

        if (!StringUtils.isAlphanumeric(name)) {
            //if(name.equals("Co-author")) System.out.println("entering");
            String fixedName = name;

            for (char c : name.toCharArray())
                if (!Character.isLetterOrDigit(c) && c != '_') {
                    //if(name.equals("Co-author")) System.out.println("true");
                    fixedName = fixedName.replaceAll(String.valueOf(c), "_NONALPHANUMERICCHAR_");
                }

            //if(name.equals("Co-author")) System.out.println("here: " + fixedName);

            nameSwitch.put(name, fixedName);
            return fixedName;

        }

        nameSwitch.put(name, name);
        return name;
    }

    private boolean isReserved(String word) {
        for (String s : useWords)
            if (s.equals(word.toLowerCase()))
                return true;

        return false;
    }
}