/******************************************************************************* * 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(">", ">"); 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; } }