/***************************************************************************** * Copyright (c) 2008, 2009 CEA LIST. * * * 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: * Remi SCHNEKENBURGER (CEA LIST) Remi.schnekenburger@cea.fr - Initial API and implementation * Yann TANGUY (CEA LIST) yann.tanguy@cea.fr * *****************************************************************************/ package org.eclipse.papyrus.uml.tools.utils; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.uml2.uml.Collaboration; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.PackageImport; import org.eclipse.uml2.uml.PackageableElement; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.ProfileApplication; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.UMLFactory; import org.eclipse.uml2.uml.UMLPackage; /** * Utility class for <code>org.eclipse.uml2.uml.Package</code><BR> */ public class PackageUtil { /** * Apply a profile and every subprofiles to a package. Also import types defined in profile * * @param profileToApply * profile to apply on package * @param package_ * on which profiles are applied * @param withSubProfiles * true if subprofiles must be automatically imported */ public static boolean applyProfile(org.eclipse.uml2.uml.Package package_, org.eclipse.uml2.uml.Profile profileToApply, boolean withSubProfiles) { // Returns�true if the model was modified boolean isChanged = false; // if profile is not defined abort treatment if(!profileToApply.isDefined()) { return isChanged; } // if same version of profile is applied do not re-apply it ProfileApplication profileApplication = package_.getProfileApplication(profileToApply); if(profileApplication != null) { EPackage previous_definition = profileApplication.getAppliedDefinition(); EPackage new_definition = profileToApply.getDefinition(); if(previous_definition == new_definition) { return isChanged; } } // Apply main profile and import contained types package_.applyProfile(profileToApply); importTypes(package_, profileToApply); isChanged = true; if(withSubProfiles) { // Manage sub profiles List<Profile> subProfiles = new ArrayList<Profile>(); subProfiles = getSubProfiles(profileToApply); Iterator<Profile> iter = subProfiles.iterator(); while(iter.hasNext()) { Profile subProfile = iter.next(); package_.applyProfile(subProfile); importTypes(package_, subProfile); } } return isChanged; } /** * Retrieve recursively the subprofiles of package. * * @param profile * * @return an arrayList containing the subprofiles */ public static List<Profile> getSubProfiles(org.eclipse.uml2.uml.Package package_) { List<Profile> subProfiles = new ArrayList<Profile>(); Iterator<Package> iter = package_.getNestedPackages().iterator(); while(iter.hasNext()) { Object element = iter.next(); if(element instanceof Profile) { Profile currentSubProfile = (Profile)element; subProfiles.add(currentSubProfile); subProfiles.addAll(getSubProfiles(currentSubProfile)); } else if(element instanceof org.eclipse.uml2.uml.Package) { org.eclipse.uml2.uml.Package currentSubPackage = (org.eclipse.uml2.uml.Package)element; subProfiles.addAll(getSubProfiles(currentSubPackage)); } } return subProfiles; } /** * Returns the top package of the specified element, i.e. the model or profile that is the root element * * @return the top {@link Package} for the specified element */ public static Package getRootPackage(Element element) { return getRootPackage(element.getNearestPackage()); } /** * Returns the top package of the specified package, i.e. the model or profile that is the root element * * @return the top {@link Package} for the specified element */ public static Package getRootPackage(Package package_) { Element owner = package_.getOwner(); //Bug 370412: The package might not be contained in a Package //(e.g. it can be contained in a Component). Search for the nearest //package, excluding self (Package#getNearestPackage() returns self) while(owner != null && !(owner instanceof Package)) { owner = owner.getOwner(); } if(owner == null) { return package_; } return getRootPackage((Package)owner); } /** * Import public type contained in the profileToApply into pkg. * * @param profileToApply * profile that contains type to import * @param pkg * receive the types from profile */ private static void importTypes(Package pkg, Package profileToApply) { /** import public types of the profile */ // get visible members of the profile EList<PackageableElement> visibleMemb = profileToApply.visibleMembers(); Iterator<PackageableElement> iterator = visibleMemb.iterator(); while(iterator.hasNext()) { Element elemt = iterator.next(); if(elemt instanceof Package) { // if the package is a model library the import it // in the package on which the profile is applied if(((Package)elemt).isModelLibrary()) { PackageImport pi = UMLFactory.eINSTANCE.createPackageImport(); pi.setImportedPackage((Package)elemt); pkg.getPackageImports().add(pi); } } } } /** * returns the list of the names of imported packages * * @param pkg * the package that has element imports * @return the list of the name of imported packages */ public static List<String> getImportedPackagesNames(Package pkg) { List<String> packageNames = new ArrayList<String>(); // iterate through package imports of the given package Iterator<PackageImport> importedIt = pkg.getPackageImports().iterator(); while(importedIt.hasNext()) { PackageImport currentImport = importedIt.next(); // get name of the imported package and adds it to the result list String currentName = currentImport.getImportedPackage().getName(); packageNames.add(currentName); } return packageNames; } /** * Removes the last definition of a profile, and in its nested profiles * * @param thepackage * profile to clean */ // @unused public static void removeLastDefinition(Package thepackage) { removeLastDefinition(thepackage, true); } /** * Removes the last definition of a profile * * @param thepackage * profile to clean * @param recursive * boolean <code>true</code> if the clean is recursive, i.e. nested profiles must be * clean */ public static void removeLastDefinition(Package thepackage, boolean recursive) { // he wants to define if(thepackage instanceof Profile) { EPackage pak = ((Profile)thepackage).getDefinition(); ((EAnnotation)pak.eContainer()).getContents().remove(pak); } if(recursive) { Iterator<Package> it = thepackage.getNestedPackages().iterator(); while(it.hasNext()) { Package p = it.next(); removeLastDefinition(p, recursive); } } } /** * Define this package if it is a profile and its sub-profiles * * @param thePackage * the package to define (if it is a profile) */ public static void defineProfiles(Package thePackage) { // he wants to define if(thePackage instanceof Profile) { ((Profile)thePackage).define(); } Iterator<Package> it = thePackage.getNestedPackages().iterator(); while(it.hasNext()) { Package p = it.next(); defineProfiles(p); } } /** * Retrieve a type accessible in this Package, given its name. * * @param name * the name of the type to find, which must not be <code>null</code> * * @return the type found or <code>null</code> if not found. */ public static Type findTypeByName(Package pack, String name) { assert name != null : "Type Name should not be null"; // update method to find a type by its name // 1. find the direct accessible types (in the package and the imported // elements) // 2. find in the subpackages and their import // 3. find in all resources Iterator<Type> it = getAccessibleTypes(pack).iterator(); while(it.hasNext()) { Type t = it.next(); if(name.equals(t.getName())) { return t; } } Resource resource = pack.eResource(); ResourceSet resourceSet = null; if(resource != null) { resourceSet = resource.getResourceSet(); } if(resourceSet != null) { return findTypeByName(resourceSet, name); } return null; } /** * Retrieve a collaboration accessible in this Package, given its name. * * @param name * the name of the collaboration to find, which must not be <code>null</code> * * @return the collaboration found or <code>null</code> if not found. */ public static Collaboration findCollaborationByName(Package pack, String name) { assert name != null : "Collaboration Name should not be null"; // update method to find a type by its name // 1. find the direct accessible types (in the package and the imported // elements) // 2. find in the subpackages and their import // 3. find in all resources Iterator<Collaboration> it = getAccessibleCollaborations(pack).iterator(); while(it.hasNext()) { Collaboration t = it.next(); if(name.equals(t.getName())) { return t; } } Resource resource = pack.eResource(); ResourceSet resourceSet = null; if(resource != null) { resourceSet = resource.getResourceSet(); } if(resourceSet != null) { return findCollaborationByName(resourceSet, name); } return null; } /** * Returns a type given its name from a resource set. * * @param resourceSet * the resource Set * @param name * the name of the type to find. It must not be <code>null</code> * @return the found type or <code>null</code> if the type was not found */ private static Type findTypeByName(ResourceSet resourceSet, String name) { TreeIterator<Notifier> iterator = resourceSet.getAllContents(); while(iterator.hasNext()) { Notifier notifier = iterator.next(); if(notifier instanceof Type) { Type type = ((Type)notifier); if(name.equals(type.getName())) { return type; } } } return null; } /** * Returns a collaboration given its name from a resource set. * * @param resourceSet * the resource Set * @param name * the name of the collaboration to find. It must not be <code>null</code> * @return the found type or <code>null</code> if the collaboration was not found */ private static Collaboration findCollaborationByName(ResourceSet resourceSet, String name) { TreeIterator<Notifier> iterator = resourceSet.getAllContents(); while(iterator.hasNext()) { Notifier notifier = iterator.next(); if(notifier instanceof Collaboration) { Collaboration type = ((Collaboration)notifier); if(name.equals(type.getName())) { return type; } } } return null; } /** * Returns all accessible types in the model * * @param element * the element from which all resources can be accessed * @return the list of Types accessible in the model */ public static Set<Type> getAllTypes(Element element) { SortedSet<Type> set = new TreeSet<Type>(new TypeNameComparator()); Resource resource = element.eResource(); ResourceSet resourceSet = null; if(resource != null) { resourceSet = resource.getResourceSet(); } if(resourceSet != null) { TreeIterator<Notifier> iterator = resourceSet.getAllContents(); while(iterator.hasNext()) { Notifier notifier = iterator.next(); if(notifier instanceof Type && ((Type)notifier).getName() != null) { set.add(((Type)notifier)); } } } return set; } /** * Returns all accessible Collaboration in the model * * @param element * the element from which all resources can be accessed * @return the list of Collaboration accessible in the model */ public static Set<Collaboration> getAllCollaborations(Element element) { SortedSet<Collaboration> set = new TreeSet<Collaboration>(new TypeNameComparator()); Resource resource = element.eResource(); ResourceSet resourceSet = null; if(resource != null) { resourceSet = resource.getResourceSet(); } if(resourceSet != null) { TreeIterator<Notifier> iterator = resourceSet.getAllContents(); while(iterator.hasNext()) { Notifier notifier = iterator.next(); if(notifier instanceof Collaboration && ((Collaboration)notifier).getName() != null) { set.add(((Collaboration)notifier)); } } } return set; } /** * Get all possible types for an element owned by this package. * * @return a set of all available Types */ public static TreeSet<Type> getAccessibleTypes(Package pack) { TreeSet<Type> set = new TreeSet<Type>(new TypeNameComparator()); // umlTypeList is used to detect type listed twice in the proposed list // this may occurs for example with indirect import of UMLPrimitiveTypes // Set<String> umlTypeQNames = new HashSet<String>(); Iterator<NamedElement> it = pack.getMembers().iterator(); // get direct members while(it.hasNext()) { NamedElement element = it.next(); if((element instanceof Type) /* * && (!(element instanceof Relationship)) */) { // Check for redundant type // if (!umlTypeQNames.contains(element.getQualifiedName())) { // /umlTypeQNames.add(element.getQualifiedName()); // set.add((Type) element); // } set.add((Type)element); } } // Recursive call on parents if((pack.getOwner() != null) && (pack.getOwner() instanceof Package)) { Iterator<Type> itParent = PackageUtil.getAccessibleTypes(pack.getNestingPackage()).iterator(); while(itParent.hasNext()) { set.add(itParent.next()); // Type currentType = itParent.next(); // if (!umlTypeQNames.contains(currentType.getQualifiedName())) // { // umlTypeQNames.add(currentType.getQualifiedName()); // set.add(currentType); // } } } return set; } /** * Get all possible Collaboration owned by this package. * * @return a set of all available Collaborations */ public static TreeSet<Collaboration> getAccessibleCollaborations(Package pack) { TreeSet<Collaboration> set = new TreeSet<Collaboration>(new TypeNameComparator()); Iterator<NamedElement> it = pack.getMembers().iterator(); // Get direct members while(it.hasNext()) { NamedElement element = it.next(); if(element instanceof Collaboration) { set.add((Collaboration)element); } } // Recursive call on parents if((pack.getOwner() != null) && (pack.getOwner() instanceof Package)) { Iterator<Collaboration> itParent = PackageUtil.getAccessibleCollaborations(pack.getNestingPackage()).iterator(); while(itParent.hasNext()) { set.add(itParent.next()); } } return set; } /** * * * @return returns all nested elements of a package (classes, packages, interfaces, data types, * properties, operations) Returned elements are of type org.eclipse.uml2.uml.Element */ public static Set<Element> getAllNestedElements(Package thePackage) { Set<org.eclipse.uml2.uml.Element> nestedElements = new HashSet<Element>(); Iterator<org.eclipse.uml2.uml.NamedElement> i = thePackage.getOwnedMembers().iterator(); org.eclipse.uml2.uml.Element currentElement; while(i.hasNext()) { currentElement = i.next(); nestedElements.add(currentElement); // Package if(currentElement instanceof org.eclipse.uml2.uml.Package) { nestedElements.addAll((PackageUtil.getAllNestedElements((Package)currentElement))); } // Class else if(currentElement instanceof org.eclipse.uml2.uml.Class) { nestedElements.addAll(((org.eclipse.uml2.uml.Class)currentElement).getMembers()); } } return nestedElements; } /** * Load Package from a specified URI * * @param uri * URI of the file to load * @param set * ResourceSet * @return the root Package */ public static org.eclipse.uml2.uml.Package loadPackage(URI uri, ResourceSet set) { org.eclipse.uml2.uml.Package package_ = null; Resource resource = set.getResource(uri, true); if(resource != null) { package_ = (org.eclipse.uml2.uml.Package)EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE); } else { Activator.logException(new FileNotFoundException("Could not retrieve resource from URI : " + uri + ".")); } return package_; } /** * Comparator using type names */ static class TypeNameComparator implements Comparator<Type> { /** * {@inheritDoc} */ public int compare(Type o1, Type o2) { final String o1Name = ((o1.getName() != null) ? o1.getName() : ""); final String o2Name = ((o2.getName() != null) ? o2.getName() : ""); return o1Name.compareTo(o2Name); } } }