org.eclipse.umlgen.reverse.java.AbstractJava2UMLConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.umlgen.reverse.java.AbstractJava2UMLConverter.java

Source

/*******************************************************************************
 * Copyright (c) 2008 Anyware Technologies 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:
 *    David Sciamma (Anyware Technologies) - initial API and implementation
 *    Urs Zeidler   - refactored and and added some basic methods
 *    Thomas Szadel (Atos Origin) - added Javadoc support and limit the details of the import according to the visibility.
 *******************************************************************************/
package org.eclipse.umlgen.reverse.java;

import com.google.common.collect.Iterables;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
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.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.ui.JavadocContentAccess;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.uml2.common.util.CacheAdapter;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.BehavioralFeature;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.ClassifierTemplateParameter;
import org.eclipse.uml2.uml.DataType;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.Feature;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.OpaqueBehavior;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.StructuredClassifier;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.TemplateSignature;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.Usage;
import org.eclipse.uml2.uml.VisibilityKind;
import org.eclipse.umlgen.reverse.java.internal.ReversePlugin;
import org.eclipse.umlgen.reverse.java.logging.Java2UMLLogListener;
import org.eclipse.umlgen.reverse.java.logging.LogUtils;
import org.eclipse.umlgen.reverse.java.preferencesStore.Java2UMLPreferencesStoreConstants;
import org.eclipse.umlgen.reverse.java.preferencesStore.Java2UMLPreferencesStoreManager;

/**
 * The basic converter class defines a basic converting flow and provides support methods.
 */
public abstract class AbstractJava2UMLConverter {

    /** The primitive types. */
    protected static final String[] PRIMITIVE_TYPES = {
            // Java
            "boolean", "byte", "char", "double", "float", "int", "long", "short",
            // UML
            "Boolean", "Integer", "String", "UnlimitedNatural", };

    /** Name of the annotation used for Javadoc. */
    private static final String JAVA_REVERSER_DOC = "http://www.eclipse.org/umlgen/reverse/java/doc";

    /** Language. */
    private static final String BEHAVIOUR_LANGUAGE = "JAVA";

    /**
     * Enumeration for the generation of the activities.
     */
    public enum ActivityGeneration {
        /** No activity. */
        NONE,
        /** Only annotated activities. */
        ANNOTATED,
        /** All activities. */
        ALL
    }

    /** a list of model uris. */
    protected String[] importList;

    /** Resource. */
    protected Resource emfResource;

    /** Name of the model. */
    protected String modelName;

    /** Public literal object. */
    protected VisibilityKind visibility = VisibilityKind.PUBLIC_LITERAL;

    /** The java project. */
    protected IJavaProject javaProject;

    /** A HashMap of Types with a String associated. */
    protected HashMap<String, Type> typeMap = new HashMap<String, Type>();

    /** Log of the shared instance. */
    protected ILog logger = ReversePlugin.getDefault().getLog();

    /** List of port. */
    protected List<String> portList;

    /** List of state. */
    protected List<String> stateList;

    /** The package of UML Library. */
    Package umlLibrary;

    /** The package of JAVA Library. */
    Package javaLibrary;

    /**
     * Limit the details of the import by skipping all elements whose visibility is lesser than the given one.
     *
     * @param visibility
     *            The visibility.
     */
    public void setVisibility(VisibilityKind visibility) {
        this.visibility = visibility;
    }

    /**
     * Returns The max visibility to import.
     *
     * @return The visibility
     */
    public VisibilityKind getVisibility() {
        return visibility;
    }

    /**
     * set the list of uris to import.
     *
     * @param importList
     *            list imported
     */
    public void setImportList(String[] importList) {
        this.importList = importList;

    }

    /**
     * test if a primitive type.
     *
     * @param name
     *            of the types
     * @return true if is a primitive types
     */
    public static boolean isPrimitiveType(String name) {

        for (String type : PRIMITIVE_TYPES) {
            if (type.equals(name)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Convert an Package or a Java project into a UML2 model.
     *
     * @param javaElement
     *            the JavaElement
     * @param actGen
     * @return The UML2 model or <code>null</code> if the IJavaElement is not a Package or a Java Project.
     * @throws CoreException
     *             , if the resource is null or some critical error occur while importing.
     */
    private Package convert(IJavaElement javaElement, ActivityGeneration actGen) throws CoreException {
        String path = null;
        IResource res = javaElement.getResource();
        if (res != null) {
            path = res.getLocation().toOSString();
        } else {
            path = javaElement.getPath().toString();
        }
        File dir = new File(path);
        Java2UMLLogListener listener = new Java2UMLLogListener(dir, modelName);
        logger.addLogListener(listener);
        LogUtils.resetTabbing();

        if (emfResource == null) {
            throwCoreException("The resource can't be null.");
        }

        switch (javaElement.getElementType()) {
        case IJavaElement.JAVA_PROJECT:
            javaProject = (IJavaProject) javaElement;
            return doConvertion((IJavaProject) javaElement, actGen);
        case IJavaElement.PACKAGE_FRAGMENT:
            javaProject = ((IPackageFragment) javaElement).getJavaProject();
            return doConvertion((IPackageFragment) javaElement, actGen);
        case IJavaElement.PACKAGE_FRAGMENT_ROOT:
            javaProject = ((IPackageFragmentRoot) javaElement).getJavaProject();
            return doConvertion((IPackageFragmentRoot) javaElement, actGen);
        default:
            return null;
        }
    }

    /**
     * Do the convertion.
     *
     * @param packageModel
     *            the package model
     * @param actGen
     * @return The UML2 model
     */
    private Package doConvertion(IPackageFragmentRoot packageModel, ActivityGeneration actGen) {
        // Let's try to find the package before creating a new one
        Model model = null;
        for (EObject eObject : emfResource.getContents()) {
            if (eObject instanceof Model) {
                if (((Model) eObject).getName() == null) {
                    if ("".equals(modelName) || modelName == null) {
                        // Found !!
                        model = (Model) eObject;
                    }
                } else if (((Model) eObject).getName().equals(modelName)) {
                    // Found !!
                    model = (Model) eObject;
                }
            }
        }

        if (model == null) {
            model = UMLFactory.eINSTANCE.createModel();
            model.setName(modelName);
            emfResource.getContents().add(model);
            LogUtils.logCreation(null, packageModel, model, null);
        }
        LogUtils.logMessage("First conversion pass");

        List<IJavaElement> fragments;
        try {
            fragments = Arrays.asList(((IPackageFragmentRoot) packageModel).getChildren());
            for (IPackageFragment f : Iterables.filter(fragments, IPackageFragment.class)) {
                convert(model, f, actGen);
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        } catch (CoreException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        }

        LogUtils.logMessage("Second pass : generating package usages");
        // Generic post-process : generate package usages
        generatePackageUsages(model);
        return model;

    }

    /**
     * Convert an Package or a Java project into a UML2 profile.
     *
     * @param javaElement
     *            the JavaElement
     * @param actGen
     * @return The UML2 model or <code>null</code> if the IJavaElement is not a Package or a Java Project.
     * @throws CoreException
     */
    protected Package convert2Profile(IJavaElement javaElement, ActivityGeneration actGen) throws CoreException {
        return convert(javaElement, actGen);
    }

    /**
     * Convert a Java Package Fragment into a UML2 PAckage and update the given UML2 Model.
     *
     * @param model
     *            The UML2 model where the Package must be inserted
     * @param fragment
     *            the Package Fragment
     * @param actGen
     * @return The updated UML2 model.
     * @throws CoreException
     */
    public Model convert(Model model, IPackageFragment fragment, ActivityGeneration actGen) throws CoreException {
        LogUtils.logEntering(fragment, null);
        initializeModel(model);

        Package packageObject = findOrCreatePackage(model, fragment);
        LogUtils.logEntering(packageObject, null);

        createTypes(packageObject, fragment);
        initializeTypes(typeMap, packageObject, fragment);
        createAssociations(packageObject);

        if (actGen == ActivityGeneration.ALL || actGen == ActivityGeneration.ANNOTATED) {
            LogUtils.logMessage("Generic post-process : Creating activities");
            generateActivities(packageObject, fragment, actGen == ActivityGeneration.ANNOTATED);
        }
        LogUtils.logExiting();
        LogUtils.logExiting();
        return model;
    }

    /**
     * Generates activity model.
     *
     * @param packageObject
     * @param fragment
     * @param isAnnotatedOnly
     */
    protected void generateActivities(Package packageObject, IPackageFragment fragment, boolean isAnnotatedOnly) {
        try {
            for (IJavaElement javaElement : fragment.getChildren()) {
                if (javaElement instanceof org.eclipse.jdt.internal.core.CompilationUnit) {
                    LogUtils.logEntering(javaElement, "Creating activities");
                    org.eclipse.jdt.internal.core.CompilationUnit unit = (org.eclipse.jdt.internal.core.CompilationUnit) javaElement;
                    ASTParser parser = ASTParser.newParser(AST.JLS3); // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4,
                    // 1.5, 1.6
                    parser.setSource(unit);
                    // In order to parse 1.5 code, some compiler options need to be set to 1.5
                    Map options = JavaCore.getOptions();
                    JavaCore.setComplianceOptions(JavaCore.VERSION_1_5, options);
                    parser.setCompilerOptions(options);
                    CompilationUnit result = (CompilationUnit) parser.createAST(null);

                    result.accept(new JavaReverseCUVisitor(packageObject, isAnnotatedOnly, null));
                    LogUtils.logExiting();
                }
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
            LogUtils.logExiting();
        }
    }

    /**
     * Initialize all types.
     *
     * @param allTypes
     *            a HashMap oh all types
     * @param packageObject
     * @param fragment
     *            a fragment of the Package
     * @throws JavaModelException
     */
    protected abstract void initializeTypes(HashMap<String, Type> allTypes, Package packageObject,
            IPackageFragment fragment) throws JavaModelException;

    /**
     * process all types.
     *
     * @param packageObject
     * @param types
     * @throws JavaModelException
     * @return a HashMap of Types with the String associated
     */
    protected abstract HashMap<String, Type> processTypes(Namespace packageObject, IType[] types)
            throws JavaModelException;

    /**
     * creates the root package.
     *
     * @return a package
     */
    protected abstract Package findOrCreateRootPackage();

    /**
     * Creates the necessary resources to process the import, like creating of imports or loading the UML
     * metamodel.
     *
     * @param model
     *            a package model
     * @throws CoreException
     */
    protected abstract void initializeModel(Package model) throws CoreException;

    /**
     * Convert a Java project into a UML2 model.
     *
     * @param project
     *            the Java Project
     * @param actGen
     * @return The UML2 model.
     * @throws CoreException
     */
    private Package doConvertion(IJavaProject project, ActivityGeneration actGen) throws CoreException {
        LogUtils.logEntering(project, null);
        Package model = findOrCreateRootPackage();

        initializeModel(model);

        LogUtils.logMessage("Creating types ");
        IPackageFragment[] children = project.getPackageFragments();
        for (IPackageFragment fragment : children) {
            if (fragment.getCompilationUnits().length > 0) {
                LogUtils.logEntering(fragment, null);
                Package packageObject = findOrCreatePackage(model, fragment);
                if (packageObject != null) {
                    createTypes(packageObject, fragment);
                }
                LogUtils.logExiting();
            }
        }

        LogUtils.logMessage("Initializing types");
        for (IPackageFragment fragment : children) {
            if (fragment.getCompilationUnits().length > 0) {
                LogUtils.logEntering(fragment, null);
                Package packageObject = findOrCreatePackage(model, fragment);
                if (packageObject != null) {
                    initializeTypes(typeMap, packageObject, fragment);
                }
                LogUtils.logExiting();
            }
        }

        LogUtils.logMessage("Generic post-process : Creating usages and associations");
        for (IPackageFragment fragment : children) {
            if (fragment.getCompilationUnits().length > 0) {
                LogUtils.logEntering(fragment, null);
                Package packageObject = findOrCreatePackage(model, fragment);
                // createUsages to move as an action on the UML model
                if (!avoidDependenciesComputing() && packageObject != null) {
                    createUsages(packageObject);
                }
                if (packageObject != null) {
                    createAssociations(packageObject);
                }
                LogUtils.logExiting();
            }
        }

        LogUtils.logMessage("Generic post-process : Creating activities");
        if (actGen == ActivityGeneration.ALL || actGen == ActivityGeneration.ANNOTATED) {
            for (IPackageFragment fragment : children) {
                if (fragment.getCompilationUnits().length > 0) {
                    LogUtils.logEntering(fragment, null);
                    Package packageObject = findOrCreatePackage(model, fragment);
                    if (packageObject != null) {
                        generateActivities(packageObject, fragment, actGen == ActivityGeneration.ANNOTATED);
                    }
                    LogUtils.logExiting();
                }
            }
        }
        return model;
    }

    /**
     * Convert a Java project into a UML2 model.
     *
     * @param packageModel
     *            the Java Package
     * @param actGen
     * @return The UML2 model.
     * @throws CoreException
     */
    private Model doConvertion(IPackageFragment packageModel, ActivityGeneration actGen) throws CoreException {
        // Let's try to find the package before creating a new one
        Model model = null;
        for (EObject eObject : emfResource.getContents()) {
            if (eObject instanceof Model) {
                if (((Model) eObject).getName() == null) {
                    if (modelName == null || "".equals(modelName)) {
                        // Found !!
                        model = (Model) eObject;
                    }
                } else if (((Model) eObject).getName().equals(modelName)) {
                    // Found !!
                    model = (Model) eObject;
                }

            }
        }

        if (model == null) {
            model = UMLFactory.eINSTANCE.createModel();
            model.setName(modelName);
            emfResource.getContents().add(model);
            LogUtils.logCreation(null, packageModel, model, null);
        }
        LogUtils.logMessage("First conversion pass");
        convert(model, packageModel, actGen);

        LogUtils.logMessage("Second pass : generating package usages");
        // Generic post-process : generate package usages
        generatePackageUsages(model);
        return model;
    }

    /**
     * Generate package Usages.
     *
     * @param umlPack
     *            the UML package
     */
    private void generatePackageUsages(Package umlPack) {
        createUsages(umlPack);
        for (EObject obj : umlPack.getPackagedElements()) {
            if (obj instanceof Package) {
                generatePackageUsages((Package) obj);
            }
        }
    }

    /**
     * Resolve a type in the context of another type using imports and inheritance.
     *
     * @param element
     *            : the element from which we get the Model
     * @param type
     *            : the enclosing type
     * @param fullyQualifiedName
     *            : the name of the type we want to resolve
     * @return : the resolved type fully qualified name
     */
    protected String resolveTypeInContext(Element element, IType type, String fullyQualifiedName) {
        if (Java2UMLConverter.isPrimitiveType(fullyQualifiedName)) {
            return fullyQualifiedName;
        }
        String[][] ancestorType;
        try {
            ancestorType = type.resolveType(fullyQualifiedName);
            if (ancestorType != null && ancestorType[0] != null) {
                if (ancestorType[0][0] == null || ancestorType[0][0].length() == 0) {
                    return ancestorType[0][1];
                } else {
                    return ancestorType[0][0].concat(".").concat(ancestorType[0][1]);
                }
            }
            if (type.getParent().getElementType() == IJavaElement.TYPE) {
                IType parentType = (IType) type.getParent();
                ancestorType = parentType.resolveType(fullyQualifiedName);
                if (ancestorType != null && ancestorType[0] != null) {
                    if (ancestorType[0][0] == null) {
                        return ancestorType[0][1];
                    } else {
                        return ancestorType[0][0].concat(".").concat(ancestorType[0][1]);
                    }
                }
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        }
        if (type.getCompilationUnit() != null) {
            try {
                IImportDeclaration[] allImports = type.getCompilationUnit().getImports();
                for (IImportDeclaration importDeclaration : allImports) {
                    if (importDeclaration.getElementName().endsWith("*")) {
                        String importPackage = importDeclaration.getElementName().substring(0,
                                importDeclaration.getElementName().lastIndexOf("."));
                        String invisibleImport = findPossibleExistingType(element, importPackage,
                                fullyQualifiedName);
                        if (invisibleImport != null) {
                            return importPackage.concat(".").concat(invisibleImport);
                        }
                    }
                    if (importDeclaration.getElementName().endsWith(fullyQualifiedName)) {
                        return importDeclaration.getElementName();
                    }
                }
            } catch (JavaModelException e) {
                e.printStackTrace();
                LogUtils.logThrowable(e);
            }

        }
        return fullyQualifiedName;
    }

    /**
     * Explore an Import Package in the model to find a Type possibly created.
     *
     * @param element
     *            : the element
     * @param packageName
     *            : the name of the package we want to explore
     * @param typeName
     *            : the name of the type
     * @return : the type name if the type is found
     */
    private String findPossibleExistingType(Element element, String packageName, String typeName) {
        StringTokenizer tokenizer = new StringTokenizer(packageName, ".");

        Package parent = element.getModel();
        Package packageObject = null;

        int tokensCount = tokenizer.countTokens();

        for (int i = 0; i < tokensCount && parent != null; i++) {
            String pathElementName = tokenizer.nextToken();
            packageObject = ((Package) parent).getNestedPackage(pathElementName, false, UMLPackage.Literals.PACKAGE,
                    false);
            parent = packageObject;
        }
        if (parent != null && parent.getOwnedType(typeName, false, UMLPackage.Literals.TYPE, false) != null) {
            return typeName;
        }
        return null;
    }

    /**
     * finds or create a package in the model for the fragment.
     *
     * @param model
     *            : the package model
     * @param fragment
     * @return Package
     */
    protected Package findOrCreatePackage(Package model, IPackageFragment fragment) {
        String qualifiedName = fragment.getElementName();
        return findOrCreatePackage(model, qualifiedName);
    }

    /**
     * finds or create a package in the model from the qualifed package name.
     *
     * @param model
     *            : the model package
     * @param packageQName
     *            the qualified name of the package
     * @return packageObject
     */
    protected Package findOrCreatePackage(Package model, String packageQName) {
        // Creates recursively the hierarchy of packages
        Package packageObject = findPackageInModel(model, packageQName);

        // search in the import package
        if (packageObject == null && model != null) {
            for (Package importedPackage : model.getImportedPackages()) {
                packageObject = findPackageInModel(importedPackage, packageQName);
                if (packageObject != null) {
                    return packageObject;
                }
            }
        }
        // if the package is not found, create it
        if (packageObject == null && model != null) {
            packageObject = createPackage(model, packageQName);
            LogUtils.logCreation(null, null, packageObject, null);
        }
        return packageObject;
    }

    /**
     * finds a package in the model from the qualifed package name.
     *
     * @param model
     *            : the model package
     * @param packageQName
     *            the qualified name of the package
     * @return packageObject
     */
    protected Package findPackageInModel(Package model, String packageQName) {
        // Creates recursively the hierarchy of packages
        StringTokenizer tokenizer = new StringTokenizer(packageQName, ".");
        Package parent = model;
        Package packageObject = model;

        // search the package if not found, search in the imported package, if not found, create it
        while (tokenizer.hasMoreTokens() && packageObject != null) {
            String packageName = tokenizer.nextToken();
            packageObject = parent.getNestedPackage(packageName);
            parent = packageObject;
        }
        return packageObject;
    }

    /**
     * create a package in the model from the qualifed package name.
     *
     * @param model
     *            : the model package
     * @param packageQName
     *            the qualified name of the package
     * @return packageObject
     */
    protected Package createPackage(Package model, String packageQName) {
        // Creates recursively the hierarchy of packages
        StringTokenizer tokenizer = new StringTokenizer(packageQName, ".");
        Package parent = model;
        Package packageObject = model;

        // search the package if not found, search in the imported package, if not found, create it
        while (tokenizer.hasMoreTokens()) {
            String packageName = tokenizer.nextToken();
            packageObject = parent.getNestedPackage(packageName);
            if (packageObject == null) {
                packageObject = parent.createNestedPackage(packageName);
                LogUtils.logCreation(null, packageName, packageObject, " Created from AbstractJava2UMLConverter");
            }
            parent = packageObject;
        }
        return packageObject;
    }

    /**
     * create a data type (intermediare package will be created).
     *
     * @param model
     *            : the model package the target model
     * @param qualifiedName
     *            the qualifed name of the type to retrieve
     * @return type
     */
    protected Type createDataType(Package model, String qualifiedName) {
        Type type = model.getOwnedType(qualifiedName, false, UMLPackage.Literals.TYPE, false);

        if (isPrimitiveType(qualifiedName)) {
            if (type == null && umlLibrary != null) {
                type = umlLibrary.getOwnedType(qualifiedName);
            }
            if (type == null && javaLibrary != null) {
                type = javaLibrary.getOwnedType(qualifiedName);
            }
        }
        if (type != null) {
            return type;
        }

        StringTokenizer tokenizer = new StringTokenizer(qualifiedName, ".");
        Package parent = model;
        Package packageObject = model;
        Classifier classifier = null;
        int tokensCount = tokenizer.countTokens();

        for (int i = 0; i < tokensCount - 1; i++) {
            String packageName = tokenizer.nextToken();
            // examine for the last token if it is a Classifier (that include the future type)
            if (i == tokensCount - 2) {
                classifier = (Classifier) parent.getMember(packageName, false, UMLPackage.Literals.CLASSIFIER);
            }
            if (classifier == null) {
                packageObject = ((Package) parent).getNestedPackage(packageName, false, UMLPackage.Literals.PACKAGE,
                        true);
            }
            parent = packageObject;
        }

        String dataTypeName = qualifiedName.substring(qualifiedName.lastIndexOf(".") + 1, qualifiedName.length());

        // Imported types
        if (importList != null) {
            for (String imp : importList) {
                try {
                    Package lib = (Package) load(URI.createURI(imp));

                    if (lib instanceof Model) {
                        type = lib.getOwnedType(qualifiedName);
                        if (type != null) {
                            model.createElementImport(type);
                            return type;
                        }

                        if (lib.getOwnedMember(dataTypeName) instanceof Type) {
                            return (Type) lib.getOwnedMember(dataTypeName);
                        }
                        List<Package> liste = lib.getNestedPackages();
                        for (PackageableElement pack : liste) {
                            type = ((Package) pack).getOwnedType(dataTypeName);
                            if (type != null) {
                                if (model.getElementImport(type) != null) {
                                    model.createElementImport(type);
                                }
                                return type;
                            }
                        }
                    }
                } catch (CoreException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    LogUtils.logThrowable(e);
                }
            }
        }
        if (type == null) {
            type = (DataType) parent.getOwnedType(dataTypeName, false, UMLPackage.Literals.DATA_TYPE, true);
        }
        return type;
    }

    /**
     * Find Type in the target model.
     *
     * @param model
     *            : the target model
     * @param qualifiedName
     *            : the qualifed name of the type to retrieve
     * @return type
     */
    protected Type findTypeInModel(Package model, String qualifiedName) {
        Type type = model.getOwnedType(qualifiedName, false, UMLPackage.Literals.TYPE, false);
        if (type != null) {
            return type;
        }
        StringTokenizer tokenizer = new StringTokenizer(qualifiedName, ".");
        Package parent = model;
        Package packageObject = model;
        Classifier classifier = null;
        int tokensCount = tokenizer.countTokens();

        for (int i = 0; i < tokensCount - 1; i++) {
            String packageName = tokenizer.nextToken();
            // examine for the last token if it is a Classifier (that include the future type)
            if (i == tokensCount - 2) {
                classifier = (Classifier) parent.getMember(packageName, false, UMLPackage.Literals.CLASSIFIER);
            }
            if (classifier == null) {
                packageObject = ((Package) parent).getNestedPackage(packageName, false, UMLPackage.Literals.PACKAGE,
                        false);
                if (packageObject == null) {
                    return null;
                }
            }
            parent = packageObject;
        }

        String dataTypeName = qualifiedName.substring(qualifiedName.lastIndexOf(".") + 1, qualifiedName.length());
        if (classifier != null) {
            type = (Type) classifier.getOwnedMember(dataTypeName, false, UMLPackage.Literals.TYPE);
        } else {
            type = parent.getOwnedType(dataTypeName, false, UMLPackage.Literals.CLASSIFIER, false);
        }
        return type;
    }

    /**
     * Loads an uml model from the uri.
     *
     * @param uri
     * @return pPackage
     * @throws CoreException
     *             : Error with the package.
     */
    protected org.eclipse.uml2.uml.Package loadUML2Model(URI uri) throws CoreException {

        ResourceSet resourceSet = new ResourceSetImpl();
        org.eclipse.uml2.uml.Package pPackage = null;

        try {
            Resource resource = resourceSet.getResource(uri, true);
            pPackage = (org.eclipse.uml2.uml.Package) EcoreUtil.getObjectByType(resource.getContents(),
                    UMLPackage.eINSTANCE.getPackage());
        } catch (WrappedException we) {
            LogUtils.logThrowable(we);
            throwCoreException(we.getMessage());
        }
        return pPackage;
    }

    /**
     * Checks for qualified name.
     *
     * @param name
     * @return boolean
     */
    protected boolean isQualifiedName(String name) {
        return name.indexOf(".") != -1;
    }

    /**
     * A lookup for the root package.
     *
     * @param packageObject
     * @return parentPackage
     */
    protected Package findRootPackage(Package packageObject) {
        Package parentPackage = (Package) packageObject.getOwner();
        // it is the root package so we return it
        if (parentPackage == null) {
            return packageObject;
        }

        while (parentPackage.getOwner() != null) {
            parentPackage = (Package) parentPackage.getOwner();
        }

        return parentPackage;
    }

    /**
     * Checks the model imports for a type.
     *
     * @param model
     *            : the model package
     * @param typeName
     *            : the name of the type
     * @return Type
     */
    protected Type findinImportPackages(Package model, String typeName) {

        String find = " findinImportPackages ";

        if ("void".equals(typeName) || model == null) {
            LogUtils.logCreation(null, model, typeName, find + typeName);
            return null;
        }

        PackageableElement importedMember = model.getImportedMember(typeName);
        if (importedMember instanceof Type) {
            LogUtils.logCreation(null, model, importedMember, find + typeName);
            return (Type) importedMember;
        }

        for (Package importedPackage : model.getImportedPackages()) {
            Type type = findTypeInModel(importedPackage, typeName);

            if (type != null) {
                LogUtils.logCreation(null, model, type, find + typeName);
                return type;
            }
            for (Package pack : importedPackage.getNestedPackages()) {
                NamedElement elt = pack.getOwnedMember(typeName);
                if (elt instanceof Type) {
                    LogUtils.logCreation(null, model, elt, find + typeName);
                    return (Type) elt;
                }
            }
        }
        LogUtils.logCreation(null, model, null, find + typeName);
        return null;
    }

    /**
     * Finds a type or creates it.
     *
     * @param packageObject
     * @param typeName
     *            : the name of the type
     * @return type
     */
    protected Type findOrCreateType(Package packageObject, String typeName) {

        // first check: Look for the type in the typeMap map (all the types created during the type creation
        // process)
        Type type = typeMap.get(typeName);

        // second check: retrieve the type in the target model
        if (type == null && packageObject.getModel() != null) {
            type = findTypeInModel(packageObject.getModel(), typeName);
        }

        // third check: retrieve type in imported target model
        if (type == null) {
            type = findinImportPackages(packageObject.getModel(), typeName);
        }

        // fourth check: retrieve type as generic type
        if (type == null) {
            type = findGenericType(packageObject.getModel(), typeName);
        }

        // the type is not found, create a data type in the correct package (intermediate packages will be
        // created)
        if (typeName != null && !"void".equals(typeName)) {
            if (isPrimitiveType(typeName)) {
                if (type == null && umlLibrary != null) {
                    type = umlLibrary.getOwnedType(typeName);
                }
                if (type == null && javaLibrary != null) {
                    type = javaLibrary.getOwnedType(typeName);
                }
            }
            if (type == null) {
                type = createNotFoundDataType(packageObject.getModel(), typeName);
            }
        }
        return type;
    }

    /**
     * Create not found classes as DataType (separate method in order to be able to change strategy : for
     * instance look inside imported models, or filter some element).
     *
     * @param packageObject
     * @param typeName
     *            a name of type
     * @return type
     */
    protected Type createNotFoundDataType(Package packageObject, String typeName) {
        Type type = createDataType(packageObject.getModel(), typeName);
        return type;
    }

    /**
     * Return a newElement or the old one if the new one is also a DataType.
     *
     * @param existing
     *            DataType that was created because we need to type properties before reversing the Classifier
     *            or Interface
     * @param newElement
     *            : the element targeted by all properties or other that need it
     * @return the newElement or the old one if the new one is also a DataType.
     */
    public Type muteDataType(Type existing, Type newElement) {
        if (newElement instanceof DataType) {
            return (DataType) existing;
        }
        ECrossReferenceAdapter crossAdpater = CacheAdapter.getCrossReferenceAdapter(existing);
        if (crossAdpater != null) {
            for (Setting aSetting : crossAdpater.getInverseReferences(existing, true)) {
                EObject eObject = aSetting.getEObject();
                if (aSetting.getEStructuralFeature() instanceof EReference) {
                    EReference ref = (EReference) aSetting.getEStructuralFeature();
                    if (!ref.isContainment() && !ref.isUnsettable() && ref.isChangeable()) {
                        if (ref.isMany() && !ref.isDerived()) {
                            EList<EObject> candidates = new BasicEList<EObject>(
                                    (EList<EObject>) eObject.eGet(aSetting.getEStructuralFeature(), true));
                            if (candidates.contains(existing)) {
                                candidates.set(candidates.indexOf(existing), newElement);
                                eObject.eSet(ref, candidates);
                            }
                        } else if (eObject.eGet(aSetting.getEStructuralFeature(), true).equals(existing)) {
                            eObject.eSet(aSetting.getEStructuralFeature(), newElement);
                        }
                    }
                } else if (aSetting.getEStructuralFeature() instanceof EAttribute) {
                    EAttribute ref = (EAttribute) aSetting.getEStructuralFeature();
                    if (eObject.eGet(ref, true).equals(existing)) {
                        if (!ref.isUnsettable() && ref.isChangeable()) {
                            eObject.eSet(aSetting.getEStructuralFeature(), newElement);
                        }
                    }
                }
            }
        }
        return newElement;
    }

    /**
     * looks for a generic type.
     *
     * @param packageObject
     * @param interfaceName
     *            the name of the interface
     * @return Type or null
     */
    protected Type findGenericType(Package packageObject, String interfaceName) {
        int indexOf = interfaceName.indexOf('<');
        if (indexOf > 0) {
            String name = interfaceName.substring(0, indexOf);
            return findTypeInModel(packageObject, name);
        }
        return null;
    }

    /**
     * Creates the associations for the types in the package.
     *
     * @param packageObject
     * @throws JavaModelException
     */
    protected void createAssociations(Package packageObject) throws JavaModelException {
        List<PackageableElement> workingCopy = new ArrayList<PackageableElement>(
                packageObject.getPackagedElements());
        for (PackageableElement element : workingCopy) {
            if (element instanceof Interface) {
                LogUtils.logEntering(element, "Creating associations");
                Interface interfaceObject = (Interface) element;
                Iterator<Property> itProp = interfaceObject.getOwnedAttributes().iterator();
                while (itProp.hasNext()) {
                    Property property = itProp.next();
                    Type targetType = property.getType();
                    if (targetType instanceof StructuredClassifier || targetType instanceof Interface) {
                        if (!(targetType.getOwner() instanceof TemplateParameter)) {
                            createAssociation(property);
                        }
                    }
                }
                LogUtils.logExiting();
            }
            if (element instanceof StructuredClassifier) {
                LogUtils.logEntering(element, "Creating associations");
                StructuredClassifier classifierObject = (StructuredClassifier) element;
                for (Property property : classifierObject.getOwnedAttributes()) {
                    Type targetType = property.getType();
                    if (targetType instanceof StructuredClassifier || targetType instanceof Interface) {
                        if (!(targetType.getOwner() instanceof TemplateParameter)) {
                            createAssociation(property);
                        }
                    }
                }
                LogUtils.logExiting();
            }
        }
    }

    /**
     * Creates an association between the owner of the property and the type.
     *
     * @param property
     */
    protected void createAssociation(Property property) {
        if (property.getAssociation() == null) {
            Property opposite = foundOpposite(property);
            Element propOwner = property.getOwner();
            Association association = UMLFactory.eINSTANCE.createAssociation();
            association.getMemberEnds().add(property);
            if (opposite != null) {
                association.getMemberEnds().add(opposite);
                association.setName(property.getName() + "_" + opposite.getName());
            } else {
                Property target = association.createOwnedEnd("target", (Type) propOwner);
                association.setName(property.getName() + "_" + target.getName());
            }
            property.getNearestPackage().getPackagedElements().add(association);
            LogUtils.logCreation(null, null, property, null);
        }
    }

    /**
     * Found the opposite of the property.
     *
     * @param source
     *            the source property
     * @return target or null
     */
    protected Property foundOpposite(Property source) {
        Property target = null;

        Type propType = source.getType();
        Element propOwner = source.getOwner();
        if (propType instanceof StructuredClassifier || propType instanceof Interface) {
            // Search if the property type has a property of the type of
            // propOwner
            List<Property> properties = null;
            if (propType instanceof StructuredClassifier) {
                properties = ((StructuredClassifier) propType).getOwnedAttributes();
            }
            if (propType instanceof Interface) {
                properties = ((Interface) propType).getOwnedAttributes();
            }

            Iterator<Property> it = properties.iterator();
            while (it.hasNext() && target == null) {
                Property prop = it.next();
                // Check that is a different property
                if (prop != source && propOwner.equals(prop.getType())) {
                    target = prop;
                }
            }
        }

        return target;
    }

    /**
     * Creates the types of the fragment in the package.
     *
     * @param packageObject
     * @param fragment
     * @throws JavaModelException
     */
    protected void createTypes(Package packageObject, IPackageFragment fragment) throws JavaModelException {
        for (IJavaElement element : fragment.getChildren()) {
            if (element instanceof ICompilationUnit) {
                LogUtils.logEntering(element, "Creating types");
                typeMap.putAll(processTypes(packageObject, ((ICompilationUnit) element).getTypes()));
                LogUtils.logExiting();
            } else if (element instanceof IClassFile) {
                LogUtils.logEntering(element, "Creating types");
                IClassFile cf = (IClassFile) element;
                typeMap.putAll(processTypes(packageObject, new IType[] { cf.getType() }));
                LogUtils.logExiting();
            }
        }
    }

    /**
     * Creates a type (class, enumeration, interface) in the package.
     *
     * @param packageObject
     * @param type
     * @return a Classifier
     * @throws JavaModelException
     */
    protected Classifier createTypeInPackage(Namespace packageObject, IType type) throws JavaModelException {
        if (type.isInterface()) {
            Interface interfaceObject = UMLFactory.eINSTANCE.createInterface();
            if (type.isAnnotation()) {
                interfaceObject.setName("@" + type.getElementName());
            } else {
                interfaceObject.setName(type.getElementName());
            }
            LogUtils.logCreation(null, type, interfaceObject, null);
            createTemplateParameters(type, interfaceObject);
            update(interfaceObject, type.getFlags());
            addToContainment(packageObject, interfaceObject);
            return interfaceObject;

        }
        if (isEnumeration(type)) {
            Enumeration enumeration = UMLFactory.eINSTANCE.createEnumeration();
            enumeration.setName(type.getElementName());
            LogUtils.logCreation(null, type, enumeration, null);
            update(enumeration, type.getFlags());
            addToContainment(packageObject, enumeration);
            return enumeration;
        }

        Class classObject = UMLFactory.eINSTANCE.createClass();
        classObject.setName(type.getElementName());
        LogUtils.logCreation(null, type, classObject, null);
        createTemplateParameters(type, classObject);
        update(classObject, type.getFlags());
        addToContainment(packageObject, classObject);
        return classObject;

    }

    /**
     * Test if the type is an enumeration.
     *
     * @param type
     * @return true if the type is an enumeration
     * @throws JavaModelException
     */
    protected boolean isEnumeration(IType type) throws JavaModelException {
        // java enumeration
        if (type.isEnum()) {
            return true;
        }
        // Old style translation for enumeration : no methods, only public static final fields
        if (type.isClass() && type.getMethods().length == 0) {
            for (IField enum0 : type.getFields()) {
                if (!Flags.isPublic(enum0.getFlags())) {
                    return false;
                }
                if (!Flags.isStatic(enum0.getFlags())) {
                    return false;
                }
                if (!Flags.isFinal(enum0.getFlags())) {
                    return false;
                }
            }
            return true;
        }
        // Otherwise
        return false;
    }

    /**
     * Creates a template parameter for a classifier (a generic).
     *
     * @param type
     * @param classObject
     * @throws JavaModelException
     */
    protected void createTemplateParameters(IType type, Classifier classObject) throws JavaModelException {
        LogUtils.logEntering(type, "Creating template parameters");
        ITypeParameter[] typeParameters = type.getTypeParameters();
        if (typeParameters.length > 0) {
            TemplateSignature templateSignature = classObject.createOwnedTemplateSignature();

            for (ITypeParameter typeParameter : typeParameters) {
                ClassifierTemplateParameter classifierTemplateParameter = UMLFactory.eINSTANCE
                        .createClassifierTemplateParameter();
                templateSignature.getOwnedParameters().add(classifierTemplateParameter);

                ParameterableElement parameteredElement = classifierTemplateParameter
                        .createOwnedParameteredElement(UMLPackage.Literals.CLASS);
                if (parameteredElement instanceof Class) {
                    Class clazz = (Class) parameteredElement;
                    clazz.setName(typeParameter.getElementName());
                } // end of if (parameteredElement instanceof Class)
                LogUtils.logCreation(type, typeParameter, parameteredElement, null);
            }
        }
        LogUtils.logExiting();
    }

    /**
     * Adds a classifier to it containment feature.
     *
     * @param packageObject
     * @param classifierObject
     */
    protected void addToContainment(Namespace packageObject, Classifier classifierObject) {
        if (packageObject instanceof Package) {
            Package po = (Package) packageObject;
            po.getPackagedElements().add(classifierObject);
            return;
        } // end of if (packageObject instanceof Package)
        if (packageObject instanceof Class) {
            Class clazz = (Class) packageObject;
            clazz.getNestedClassifiers().add(classifierObject);
            return;
        } // end of if (packageObject instanceof Class)
        if (packageObject instanceof Interface) {
            Interface i = (Interface) packageObject;
            i.getNestedClassifiers().add(classifierObject);
            return;
        } // end of if (packageObject instanceof Class)

    }

    /**
     * Looks up a template parameter in an element.
     *
     * @param element
     * @param fieldName
     *            the name of the field
     * @return classifier or null
     */
    protected Type findTemplateParameter(Element element, String fieldName) {
        for (Element child : element.allOwnedElements()) {
            if (child instanceof Classifier) {
                Classifier classifier = (Classifier) child;
                if (classifier.getName().equals(fieldName)) {
                    return classifier;
                }
            } else if (child instanceof Operation) {
                Operation operation = (Operation) child;
            }
        }
        return null;
    }

    /**
     * Update the visibility.
     *
     * @param element
     * @param flags
     * @throws JavaModelException
     */
    protected void update(NamedElement element, int flags) throws JavaModelException {
        if (Flags.isAbstract(flags)) {
            if (element instanceof Classifier) {
                Classifier cl = (Classifier) element;
                cl.setIsAbstract(true);
            } else if (element instanceof BehavioralFeature) {
                BehavioralFeature bf = (BehavioralFeature) element;
                bf.setIsAbstract(true);
            }
        }

        if (Flags.isStatic(flags)) {
            if (element instanceof BehavioralFeature) {
                BehavioralFeature bf = (BehavioralFeature) element;
                bf.setIsStatic(true);
            } else if (element instanceof Feature) {
                Feature feature = (Feature) element;
                feature.setIsStatic(true);
            }
        }

        if (Flags.isFinal(flags)) {
            if (element instanceof BehavioralFeature) {
                BehavioralFeature bf = (BehavioralFeature) element;
                bf.setIsLeaf(true);
            } else if (element instanceof Feature) {
                Feature feature = (Feature) element;
                feature.setIsLeaf(true);
            }
        }

        if (Flags.isPrivate(flags)) {
            element.setVisibility(VisibilityKind.PRIVATE_LITERAL);
        } else if (Flags.isProtected(flags)) {
            element.setVisibility(VisibilityKind.PROTECTED_LITERAL);
        } else if (Flags.isPublic(flags)) {
            element.setVisibility(VisibilityKind.PUBLIC_LITERAL);
        } else if (Flags.isPackageDefault(flags)) {
            if (element instanceof Property) {
                Property property = (Property) element;
                if (property.getOwner() instanceof Interface) {
                    Interface i = (Interface) property.getOwner();
                    property.setVisibility(i.getVisibility());
                }
            } else if (element instanceof Operation) {
                Operation op = (Operation) element;
                if (op.getOwner() instanceof Interface) {
                    Interface i = (Interface) op.getOwner();
                    op.setVisibility(i.getVisibility());
                }
            } else {
                element.setVisibility(VisibilityKind.PACKAGE_LITERAL);
            }
        }
    }

    /**
     * Returns the simple name of a fragment.
     *
     * @param fragment
     * @return name
     */
    protected String getName(IPackageFragment fragment) {
        String name = "";
        String fullName = fragment.getElementName();
        int dotIndex = fullName.lastIndexOf('.');
        if (dotIndex > 0) {
            name = fullName.substring(dotIndex + 1);
        }

        return name;
    }

    /**
     * Check whether the member can be imported or not according to its visibility.
     *
     * @param member
     *            The member.
     * @return True if it can, false otherwise.
     * @throws JavaModelException
     */
    protected boolean canBeImported(IMember member) throws JavaModelException {
        int flag = member.getFlags();
        switch (visibility) {
        case PRIVATE_LITERAL:
            return true; // All is accepted
        case PROTECTED_LITERAL:
            return Flags.isPublic(flag) || Flags.isPackageDefault(flag) || Flags.isProtected(flag);
        case PACKAGE_LITERAL:
            return Flags.isPublic(flag) || Flags.isPackageDefault(flag);
        case PUBLIC_LITERAL:
        default:
            return Flags.isPublic(flag);
        }
    }

    /**
     * Check whether the element is a part of a port:communication mechanism.
     *
     * @param member
     *            The member.
     * @return True if it can, false otherwise.
     * @throws JavaModelException
     */
    protected boolean isStrucDiag(IMember member) throws JavaModelException {
        boolean ret = false;

        if ("initPortsGenerator".equals(member.getElementName())) {
            ret = true;
        } else if ("makeConnections".equals(member.getElementName())) {
            ret = true;
        }
        return ret;
    }

    /**
     * Returns the Javadoc associated to a member.
     *
     * @param member
     *            The member.
     * @return The Javadoc or empty string if none.
     * @throws JavaModelException
     *             Error during introspection.
     */
    protected String getJavadoc(IMember member) throws JavaModelException {
        Reader lReader = JavadocContentAccess.getContentReader(member, true);
        if (lReader != null) {
            try {
                BufferedReader in = new BufferedReader(lReader);
                StringBuffer javadoc = new StringBuffer();
                int c;
                boolean lReturnAdded = false;
                while ((c = in.read()) != -1) {
                    if (c == '\n' || c == '\r') {
                        // Nothing
                        if (!lReturnAdded) {
                            javadoc.append(System.getProperty("line.separator"));
                            lReturnAdded = true;
                        }
                    } else {
                        lReturnAdded = false;
                        javadoc.append((char) c);
                    }
                }
                in.close();
                return javadoc.toString();
            } catch (IOException e) {
                LogUtils.logThrowable(e);
                // Cannot occur
            }
        }
        return "";
    }

    /**
     * Find an operation.
     *
     * @param classifier
     *            The classifier.
     * @param method
     *            The method.
     * @return The operation or null if not found.
     */
    protected Operation findOperation(Classifier classifier, IMethod method) {
        try {
            BasicEList<String> paramList = new BasicEList<String>();
            for (String param : method.getParameterNames()) {
                paramList.add(param);
            }

            BasicEList<Type> paramTypeList = new BasicEList<Type>();
            for (String param : method.getParameterTypes()) {
                String typeWithoutArray = Signature.getElementType(param);
                String typeName = Signature.toString(Signature.getTypeErasure(typeWithoutArray));
                typeName = resolveTypeInContext(classifier, method.getDeclaringType(), typeName);
                Type paramType = findOrCreateType(classifier.getNearestPackage(), typeName);
                if (paramType != null) {
                    paramTypeList.add(paramType);
                }
            }
            Operation op = null;
            if (classifier instanceof Class) {
                op = ((Class) classifier).getOwnedOperation(method.getElementName(), paramList, paramTypeList,
                        false, false);
                if (op != null) {
                    op.setClass_((Class) classifier);
                }
                return op;
            }
            if (classifier instanceof Interface) {
                op = ((Interface) classifier).getOwnedOperation(method.getElementName(), paramList, paramTypeList,
                        false, false);
                if (op != null) {
                    op.setInterface((Interface) classifier);
                }
                return op;
            }
            if (classifier instanceof DataType) {
                op = ((DataType) classifier).getOwnedOperation(method.getElementName(), paramList, paramTypeList,
                        false, false);
                if (op != null) {
                    op.setDatatype((DataType) classifier);
                }
                return op;
            }
            if (classifier instanceof PrimitiveType) {
                ReversePlugin.log(
                        "The operation was not stored in the content of a Primitive Type : " + classifier.getName(),
                        IStatus.ERROR);
                op = ((PrimitiveType) classifier).getOwnedOperation(method.getElementName(), paramList,
                        paramTypeList, false, false);
                if (op != null) {
                    op.setDatatype((PrimitiveType) classifier);
                }
                return op;
            }
            // Never Happens normally
            if (classifier instanceof Enumeration) {
                ReversePlugin.log(
                        "The operation was not stored in the content of an Enumeration : " + classifier.getName(),
                        IStatus.ERROR);
                op = ((Enumeration) classifier).getOwnedOperation(method.getElementName(), paramList, paramTypeList,
                        false, false);
                if (op != null) {
                    op.setDatatype((Enumeration) classifier);
                }
                return op;
            }
            ReversePlugin.log("The operation was not stored in the content of : " + classifier.getName(),
                    IStatus.ERROR);
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        }
        return null;
    }

    /**
     * Create an opaqueBehavior containing the code of the function.
     *
     * @param operation
     *            : the operation that relates the function
     * @param sourceMethod
     *            : the IMethod element
     * @return the new FunctionBehavior
     */
    protected OpaqueBehavior createOpaqueBehavior(Operation operation, IMethod sourceMethod) {
        OpaqueBehavior opaque = UMLFactory.eINSTANCE.createOpaqueBehavior();

        // set Name
        opaque.setName(operation.getName());

        // add Parameters
        for (Parameter parameter : operation.getOwnedParameters()) {
            opaque.createOwnedParameter(parameter.getName(), parameter.getType());
        }

        // reference the operation
        opaque.setSpecification(operation);

        // set the visibility
        opaque.setVisibility(operation.getVisibility());

        // set the language (JAVA)
        opaque.getLanguages().add(BEHAVIOUR_LANGUAGE);

        // add the body
        try {
            String body = sourceMethod.getSource();
            int beginIndex = body.indexOf('{');
            int endIndex = body.lastIndexOf('}');
            if (beginIndex != -1 && endIndex != -1 && endIndex > beginIndex) {
                body = body.substring(beginIndex + 1, endIndex);
            }
            body = body.replaceAll(">", "&gt;");
            opaque.getBodies().add(body);
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        }
        return opaque;
    }

    /**
     * Update the opaquebehavior containing the code of the function.
     *
     * @param opaque
     * @param sourceMethod
     *            : the IMethod element
     */
    protected void updateOpaqueBehaviorBody(OpaqueBehavior opaque, IMethod sourceMethod) {
        // update the body
        try {
            opaque.getBodies().remove(0);
            String body = sourceMethod.getSource();
            int beginIndex = body.indexOf('{');
            int endIndex = body.lastIndexOf('}');
            if (beginIndex != -1 && endIndex != -1 && endIndex > beginIndex) {
                body = body.substring(beginIndex + 1, endIndex);

            }
            opaque.getBodies().add(body);
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        }
    }

    /**
     * Create and return an operation for a type.
     *
     * @param element
     * @param method
     * @return operationObject
     * @throws JavaModelException
     */
    protected Operation createOperation(Element element, IMethod method) throws JavaModelException {
        String methodName = method.getElementName();

        Operation operationObject = UMLFactory.eINSTANCE.createOperation();
        operationObject.setName(methodName);

        update(operationObject, method.getFlags());

        int flags = method.getFlags();
        operationObject.setIsAbstract(Flags.isAbstract(flags));
        operationObject.setIsStatic(Flags.isStatic(flags));

        attachJavadoc(operationObject, method);

        createParameters(element, operationObject, method);

        if (method.exists() && !method.isConstructor()) {
            createTemplateParameters(method, operationObject);

            String returnTypeSig = method.getReturnType();
            int arrayCount = Signature.getArrayCount(returnTypeSig);

            String returnTypeWithoutArray = Signature.getElementType(returnTypeSig);
            String returnTypeName = Signature.toString(Signature.getTypeErasure(returnTypeWithoutArray));

            Type returnType = findTemplateParameter(element, returnTypeName);
            if (returnType == null) {
                returnType = findTemplateParameter(operationObject, returnTypeName);
            }

            if (returnType == null) {
                returnTypeName = resolveTypeInContext(element, method.getDeclaringType(), returnTypeName);
                returnType = findOrCreateType(element.getNearestPackage(), returnTypeName);
            }

            // Type returnType = findOrCreateType(element.getNearestPackage(),
            // returnTypeName);
            if (returnType != null) {
                Parameter parameter = UMLFactory.eINSTANCE.createParameter();
                // parameter.setName("");
                parameter.setDirection(ParameterDirectionKind.RETURN_LITERAL);
                parameter.setType(returnType);
                // handle array case with ONE dimension
                if (arrayCount == 1) {
                    parameter.setUpper(-1);
                } else if (arrayCount > 1) {
                    // handle array case with more than ONE dimension
                    // TODO find the best way to represent it in UML
                }

                operationObject.getOwnedParameters().add(parameter);
            }
        }

        // set the container
        if (element instanceof Class) {
            operationObject.setClass_((Class) element);
        }
        if (element instanceof Interface) {
            operationObject.setInterface((Interface) element);
        }
        if (element instanceof DataType) {
            operationObject.setDatatype((DataType) element);
        }
        if (element instanceof PrimitiveType) {
            operationObject.setDatatype((PrimitiveType) element);
        }
        // Never Happens normally
        if (element instanceof Enumeration) {
            ReversePlugin.log("The operation was not stored in the content of an Enumeration : "
                    + ((Enumeration) element).getName(), IStatus.ERROR);
            operationObject.setDatatype((Enumeration) element);
        }
        return operationObject;
    }

    /**
     * Creates a template parameter for a method.
     *
     * @param method
     * @param operationObject
     * @throws JavaModelException
     *             Java error.
     */
    private void createTemplateParameters(IMethod method, Operation operationObject) throws JavaModelException {
        ITypeParameter[] typeParameters = method.getTypeParameters();
        for (ITypeParameter typeParameter : typeParameters) {
            TemplateSignature templateSignature = operationObject.getOwnedTemplateSignature();
            // FIXME See how to update the template signature
            if (templateSignature == null) {
                templateSignature = operationObject.createOwnedTemplateSignature();
                ClassifierTemplateParameter classifierTemplateParameter = UMLFactory.eINSTANCE
                        .createClassifierTemplateParameter();
                templateSignature.getOwnedParameters().add(classifierTemplateParameter);
                ParameterableElement parameteredElement = classifierTemplateParameter
                        .createOwnedParameteredElement(UMLPackage.Literals.CLASS);
                if (parameteredElement instanceof Class) {
                    Class clazz = (Class) parameteredElement;
                    clazz.setName(typeParameter.getElementName());
                } // end of if (parameteredElement instanceof Class)
            }
        }
    }

    /**
     * Creates the parameters for a method.
     *
     * @param element
     * @param operation
     * @param method
     * @throws JavaModelException
     */
    protected void createParameters(Element element, Operation operation, IMethod method)
            throws JavaModelException {
        String[] paramNames = method.getParameterNames();
        String[] paramTypeSigs = method.getParameterTypes();
        for (int i = 0; i < paramNames.length; i++) {
            String name = paramNames[i];
            String typeSig = paramTypeSigs[i];
            int arrayCount = Signature.getArrayCount(typeSig);

            Parameter parameter = UMLFactory.eINSTANCE.createParameter();
            parameter.setName(name);

            String typeWithoutArray = Signature.getElementType(typeSig);
            String typeName = Signature.toString(Signature.getTypeErasure(typeWithoutArray));

            Type paramType = findTemplateParameter(element, typeName);
            if (paramType == null) {
                typeName = resolveTypeInContext(element, method.getDeclaringType(), typeName);
                paramType = findOrCreateType(element.getNearestPackage(), typeName);
            }

            if (paramType != null) {
                parameter.setType(paramType);
            }

            // handle array case with ONE dimension
            if (arrayCount == 1) {
                parameter.setUpper(-1);
            } else if (arrayCount > 1) {
                // handle array case with more than ONE dimension
                // TODO find the best way to represent it in UML
            }
            operation.getOwnedParameters().add(parameter);
        }
    }

    /**
     * Creates and returns a property.
     *
     * @param element
     * @param field
     * @return a Property
     * @throws JavaModelException
     */
    protected Property createProperty(Element element, IField field) throws JavaModelException {
        boolean isCollection = false;
        boolean isSet = false;
        boolean isList = false;
        // no need for an isArray, see arraycount variable

        String fieldName = field.getElementName();
        String fieldTypeSig = field.getTypeSignature();
        String fieldTypeWithoutArray = Signature.getElementType(fieldTypeSig);
        Property propertyObject = null;

        int arrayCount = Signature.getArrayCount(fieldTypeSig);
        String fieldTypeName = Signature.toString(Signature.getTypeErasure(fieldTypeWithoutArray));
        Type fieldType = findTemplateParameter(element, fieldTypeName);

        if (fieldType == null) {
            fieldTypeName = resolveTypeInContext(element, field.getDeclaringType(), fieldTypeName);
            fieldType = findOrCreateType(element.getNearestPackage(), fieldTypeName);
        }

        String[] typeArguments = Signature.getTypeArguments(fieldTypeSig);
        // X<Y> types - handle collections
        if (typeArguments != null && typeArguments.length == 1) {
            // Get the X class and see if it is a subclass of Set, List or Collection
            // TODO get datatype, crawl back up packages for full qualified name,
            // get actual class, compare to collections, List, Set
            java.lang.Class<?> mainClass = null;
            try {
                mainClass = java.lang.Class.forName(fieldTypeName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                LogUtils.logThrowable(e);
            }
            if (mainClass != null && Collection.class.isAssignableFrom(mainClass)) {
                isCollection = true;
                fieldTypeWithoutArray = typeArguments[0];
                String fieldTypeWithoutArrayName = Signature
                        .toString(Signature.getTypeErasure(fieldTypeWithoutArray));
                fieldType = findTemplateParameter(element, fieldTypeWithoutArrayName);
                if (fieldType == null) {
                    fieldTypeWithoutArrayName = resolveTypeInContext(element, field.getDeclaringType(),
                            fieldTypeWithoutArrayName);
                    fieldType = findOrCreateType(element.getNearestPackage(), fieldTypeWithoutArrayName);
                }
                if (mainClass != null && Set.class.isAssignableFrom(mainClass)) {
                    isSet = true;
                } else if (mainClass != null && List.class.isAssignableFrom(mainClass)) {
                    isList = true;
                }
            }
        }

        // retrieve the affectation
        String affectation = retrieveFieldAffectation(field);

        // create the attribute
        propertyObject = null;
        String created = " created ";
        if (element instanceof Class) {
            propertyObject = ((Class) element).createOwnedAttribute(fieldName, fieldType);
            LogUtils.logCreation(element, null, propertyObject, created);
        } else if (element instanceof Enumeration) {
            propertyObject = ((Enumeration) element).createOwnedAttribute(fieldName, fieldType);
            LogUtils.logCreation(element, null, propertyObject, created);
        } else if (element instanceof Interface) {
            propertyObject = ((Interface) element).createOwnedAttribute(fieldName, fieldType);
            LogUtils.logCreation(element, null, propertyObject, created);
        }

        if (propertyObject == null) {
            ReversePlugin.log("The property can not be created.", Status.ERROR);
            return null;
        }

        attachJavadoc(propertyObject, field);
        update(propertyObject, field.getFlags());

        // No need to check the null (done with instanceof which returns always false)
        if (field.getConstant() instanceof String) {
            LiteralString defaultValue = (LiteralString) propertyObject.createDefaultValue("",
                    propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralString().eClass());
            defaultValue.setValue((String) field.getConstant());
        } else if (field.getConstant() instanceof Integer) {
            LiteralInteger defaultValue = (LiteralInteger) propertyObject.createDefaultValue("",
                    propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralInteger().eClass());
            defaultValue.setValue((Integer) field.getConstant());
        } else if (field.getConstant() instanceof Boolean) {
            LiteralBoolean defaultValue = (LiteralBoolean) propertyObject.createDefaultValue("",
                    propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralBoolean().eClass());
            defaultValue.setValue((Boolean) field.getConstant());
        } else if (affectation != null && arrayCount == 0) {
            LiteralString defaultValue = (LiteralString) propertyObject.createDefaultValue("",
                    propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralString().eClass());
            defaultValue.setValue(affectation);
        }

        // handle array case with ONE dimension
        if (arrayCount == 1) {
            propertyObject.setUpper(-1);

            if (affectation != null) {
                String size = retrieveInitDimSize(affectation, 1);
                if (size != null) {
                    LiteralString defaultValue = (LiteralString) propertyObject.createDefaultValue("",
                            propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralString().eClass());
                    defaultValue.setValue(size);
                }
            }
        } else if (arrayCount > 1) {
            // handle array case with more than ONE dimension
            String stringTypeName = resolveTypeInContext(element, field.getDeclaringType(), "String");
            Type stringType = findOrCreateType(element.getNearestPackage(), stringTypeName);
            for (int i = 1; i <= arrayCount; i++) {
                // create a qualifier property for each dimension
                String qualifierName = "dimension_" + i;
                Property prop = propertyObject.createQualifier(qualifierName, stringType);
                prop.setUpper(-1);
                if (affectation != null) {
                    String size = retrieveInitDimSize(affectation, i);
                    if (size != null) {
                        LiteralString defaultValue = (LiteralString) prop.createDefaultValue("", prop.getType(),
                                UMLFactory.eINSTANCE.createLiteralString().eClass());
                        defaultValue.setValue(size);
                    }
                }
            }
        }
        // handle Collections
        if (isCollection) {
            if (propertyObject.getUpper() < 2) {
                propertyObject.setUpper(-1);
            }
            propertyObject.setIsOrdered(false);
            propertyObject.setIsUnique(false);
        }
        // handle Sets and Lists specifically
        if (isSet) {
            if (propertyObject.getUpper() < 2) {
                propertyObject.setUpper(-1);
            }
            propertyObject.setIsUnique(true);
            propertyObject.setIsOrdered(true);
        } else if (isList) {
            if (propertyObject.getUpper() < 2) {
                propertyObject.setUpper(-1);
            }
            propertyObject.setIsOrdered(true);
            propertyObject.setIsUnique(false);
        }
        // TODO handle Maps
        return propertyObject;
    }

    /**
     * Retrieve the arraySize from an initialization.
     *
     * @param initialization
     * @param dim
     *            the dimension of the array we want to retrieve the size
     * @return the size as a String Type
     */
    private String retrieveInitDimSize(String initialization, int dim) {
        if (initialization == null) {
            return null;
        }
        int i = 1;
        while (initialization.indexOf('[') != -1) {
            int end = initialization.indexOf(']');
            if (dim == i) {
                int begin = initialization.indexOf('[');
                if (end != -1 && begin != -1 && end - begin >= 2) {
                    return initialization.substring(begin + 1, end);
                }
                return null;
            }
            if (end == -1) {
                return null;
            }
            initialization = initialization.substring(end + 1);
            i++;
        }
        return null;
    }

    /**
     * Retrieve the field affectation.
     *
     * @param field
     *            the field
     * @return the affectation found inthe type (null if no affectation
     */
    private String retrieveFieldAffectation(IField field) {
        String source;
        String intialization = null;
        try {
            source = field.getSource();

            int equalIndex = source.indexOf('=');
            int dotIndex = source.lastIndexOf(';');

            if (equalIndex != -1 && dotIndex > equalIndex) {
                intialization = source.substring(equalIndex + 1, dotIndex).trim();
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
            LogUtils.logThrowable(e);
        }
        return intialization;
    }

    /**
     * Find a property.
     *
     * @param classifier
     *            The classifier.
     * @param name
     *            The name of the property.
     * @return The property or null if not found.
     */
    protected Property findProperty(Classifier classifier, String name) {
        for (Property prop : classifier.getAllAttributes()) {
            if (prop.getName().equals(name)) {
                return prop;
            }
        }
        return null;
    }

    /**
     * Attach the javadoc to an element.
     *
     * @param element
     *            The EMF element.
     * @param member
     *            The JDT Element.
     * @throws JavaModelException
     *             Error.
     */
    protected void attachJavadoc(Element element, IMember member) throws JavaModelException {
        String javadoc = getJavadoc(member);
        if (!"".equals(javadoc)) {
            EAnnotation annotation = element.getEAnnotation(JAVA_REVERSER_DOC);
            if (annotation == null) {
                annotation = element.createEAnnotation(JAVA_REVERSER_DOC);
            }
            annotation.getDetails().put("documentation", javadoc);
        }
    }

    /**
     * Create usages (between packages for the moment).
     *
     * @param packageObject
     *            the Java Package
     */
    private void createUsages(Package packageObject) {
        ArrayList<Package> usedPackageList = new ArrayList<Package>();
        LogUtils.logEntering(packageObject, "Creating usages");
        // build the list of used packages
        for (PackageableElement elementInPackage : packageObject.getPackagedElements()) {
            if (elementInPackage instanceof Interface) {
                Interface interfaceObject = (Interface) elementInPackage;
                for (Package importedPackage : interfaceObject.getImportedPackages()) {
                    if (!usedPackageList.contains(importedPackage)) {
                        usedPackageList.add(importedPackage);
                    }
                }

                for (PackageableElement element : interfaceObject.getImportedElements()) {
                    Package importedPackage = element.getNearestPackage();
                    if (!usedPackageList.contains(importedPackage)) {
                        usedPackageList.add(importedPackage);
                    }
                }

                // destroy the imported element if it is needed ( generation RTSJ constraint)
                if (!avoidImportElement()) {
                    interfaceObject.getElementImports().clear();
                    interfaceObject.getPackageImports().clear();
                }

            } else if (elementInPackage instanceof StructuredClassifier) {

                StructuredClassifier classifierObject = (StructuredClassifier) elementInPackage;
                for (Package importedPackage : classifierObject.getImportedPackages()) {
                    if (!usedPackageList.contains(importedPackage)) {
                        usedPackageList.add(importedPackage);
                    }
                }

                for (PackageableElement element : classifierObject.getImportedElements()) {
                    Package importedPackage = element.getNearestPackage();
                    if (!usedPackageList.contains(importedPackage)) {
                        usedPackageList.add(importedPackage);
                    }
                }

                // destroy the imported element if it is needed ( generation RTSJ constraint)
                if (avoidImportElement()) {
                    classifierObject.getElementImports().clear();
                    classifierObject.getPackageImports().clear();
                }
            }
        }

        // create a Usage relation for each package used by this one
        for (Package usedPackage : usedPackageList) {
            Usage tmprel = packageObject.createUsage(usedPackage);
            tmprel.setName(packageObject.getName() + "_" + usedPackage.getName());
            LogUtils.logCreation(null, null, packageObject, null);
        }
        LogUtils.logExiting();
    }

    /**
     * Return true if the elementImport and packageImport have to be reversed.
     *
     * @return true if the elementImport and packageImport have to be reversed
     */
    protected boolean avoidImportElement() {
        if (javaProject == null) {
            return true;
        }
        IProject iProject = ResourcesPlugin.getWorkspace().getRoot().getProject(javaProject.getElementName());
        IPreferenceStore store = Java2UMLPreferencesStoreManager.getPreferenceStore(iProject);
        return store.getBoolean(Java2UMLPreferencesStoreConstants.REVERSE_IMPORTS_NAME);
    }

    /**
     * Return true if the elementImport and packageImport have to be reversed.
     *
     * @return true if the elementImport and packageImport have to be reversed
     */
    protected boolean avoidDependenciesComputing() {
        if (javaProject == null) {
            return true;
        }
        IProject iProject = ResourcesPlugin.getWorkspace().getRoot().getProject(javaProject.getElementName());
        IPreferenceStore store = Java2UMLPreferencesStoreManager.getPreferenceStore(iProject);
        return store.getBoolean(Java2UMLPreferencesStoreConstants.COMPUTE_DEPENDENCIES_NAME);
    }

    /**
     * Convenient method to throw a core exception.
     *
     * @param message
     *            : the message of the exception
     * @throws CoreException
     *             Error with a status
     */
    protected void throwCoreException(String message) throws CoreException {
        IStatus status = new Status(IStatus.ERROR, ReversePlugin.getId(), IStatus.OK, message, null);
        throw new CoreException(status);
    }

    /**
     * The convert method will convert all processable java elements to uml elements and store them in the
     * resource.
     *
     * @param javaElement
     *            : the java element
     * @param pEmfResource
     * @return a Package
     * @throws CoreException
     */
    public Package convert(IJavaElement javaElement, Resource pEmfResource) throws CoreException {
        return convert(javaElement, pEmfResource, ActivityGeneration.NONE);
    }

    /**
     * The convert method will convert all processable java elements to uml elements and store them in the
     * resource.
     *
     * @param javaElement
     *            : the jkava element
     * @param pEmfResource
     *            : the resource where the element are stored
     * @param actGen
     * @return a Package
     * @throws CoreException
     */
    public Package convert(IJavaElement javaElement, Resource pEmfResource, ActivityGeneration actGen)
            throws CoreException {
        this.emfResource = pEmfResource;
        return convert(javaElement, actGen);
    }

    /**
     * Set the model name, to the model, quite important for a profile model.
     *
     * @param modelName
     *            : the name of the model
     */
    public void setModelName(String modelName) {
        this.modelName = modelName;
    }

    /**
     * Load model as package with name uri.
     *
     * @param uri
     * @return a Package
     * @throws CoreException
     */
    protected Package load(URI uri) throws CoreException {
        Package vPackage = null;

        try {
            ResourceSet resourceSet = new ResourceSetImpl();
            // Load the requested resource
            Resource resource = resourceSet.getResource(uri, true);

            // Get the first (should be only) package from it
            vPackage = (Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE);
        } catch (WrappedException we) {
            LogUtils.logThrowable(we);
            throwCoreException(we.getMessage());
        }
        return vPackage;
    }
}