/******************************************************************************* * Copyright (c) 2014, 2015 CEA LIST 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: * E.D.Willink (CEA List) - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.pivot.uml.internal.es2as; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.ElementExtension; import org.eclipse.ocl.pivot.NamedElement; import org.eclipse.ocl.pivot.Profile; import org.eclipse.ocl.pivot.ProfileApplication; import org.eclipse.ocl.pivot.Stereotype; import org.eclipse.ocl.pivot.StereotypeExtender; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.NameUtil; /** * The ModelAnalysis captures the overall analysis of the UML M1 ProfileApplication and ElementExtensions. */ public class ModelAnalysis { public static class ElementComparator implements Comparator<Element> { public static final @NonNull ElementComparator INSTANCE = new ElementComparator(); @Override public int compare(Element o1, Element o2) { if (o1 instanceof NamedElement) { if (o1 instanceof NamedElement) { String n1 = ((NamedElement)o1).getName(); String n2 = ((NamedElement)o2).getName(); return ClassUtil.safeCompareTo(n1, n2); } else { return 1; } } else { if (o1 instanceof NamedElement) { return -1; } else { return o1.hashCode() - o2.hashCode(); } } } } protected final UML2AS.@NonNull Outer converter; protected final @NonNull ProfileAnalysis profileAnalysis; protected final @NonNull EnvironmentFactoryInternal environmentFactory; /** * Map of all Profiles Applied to each Package, populated initially by the explicit ProfileApplications and expanded to cover the *transitive applications. */ /** * All the ProfileApplication elements. */ private final @NonNull List<ProfileApplication> asProfileApplications = new ArrayList<ProfileApplication>(); // private @Nullable Map<Profile, Set<Profile>> profile2allProfiles = new HashMap<Profile, Set<Profile>>(); /** * All the Profiles that are applied to something. */ private final @NonNull Set<Profile> appliedProfiles = new HashSet<Profile>(); /** * Map from the each applied Profiles to all the profiles that are applied by the application of the profile. */ private final @NonNull Map<Profile, Set<Profile>> appliedProfile2appliedProfileClosure = new HashMap<Profile, Set<Profile>>(); /** * Map from the each package to all the profiles aplied to the package. */ private final @NonNull Map<org.eclipse.ocl.pivot.Package, @NonNull Set<Profile>> package2appliedProfileClosure = new HashMap<org.eclipse.ocl.pivot.Package, @NonNull Set<Profile>>(); private final @NonNull Map<EClass, Type> eClass2metatype = new HashMap<EClass, Type>(); /** * List of UML elements stereotyped by each UML stereotype application. * <p> * Note that the UML stereotype application object is an EDynamicObject unless the Profile has been genmodelled as * is the case for the standard UML profile(s). */ private @Nullable List<EObject> umlStereotypeApplications = null; public ModelAnalysis(UML2AS.@NonNull Outer converter, @NonNull ProfileAnalysis profileAnalysis) { this.converter = converter; this.profileAnalysis = profileAnalysis; this.environmentFactory = converter.getEnvironmentFactory(); } public void addProfile(@NonNull Profile asProfile) { appliedProfiles.add(asProfile); } public void addProfileApplication(@NonNull ProfileApplication asProfileApplication) { asProfileApplications.add(asProfileApplication); Profile asProfile = asProfileApplication.getAppliedProfile(); if (asProfile != null) { appliedProfiles.add(asProfile); } } public void addStereotypeApplication(@NonNull EObject umlStereotypeApplication) { @SuppressWarnings("null")@NonNull EClass eClass = umlStereotypeApplication.eClass(); if (UML2AS.ADD_STEREOTYPE_APPLICATION.isActive()) { if (umlStereotypeApplication instanceof DynamicEObjectImpl) { UML2AS.ADD_STEREOTYPE_APPLICATION.println(NameUtil.qualifiedNameFor(eClass)); } else { UML2AS.ADD_STEREOTYPE_APPLICATION.println(NameUtil.qualifiedNameFor(eClass)); // ADD_STEREOTYPE_APPLICATION.println(umlStereotypeApplication.toString()); } } List<EObject> umlStereotypeApplications2 = umlStereotypeApplications; if (umlStereotypeApplications2 == null) { umlStereotypeApplications = umlStereotypeApplications2 = new ArrayList<EObject>(); } umlStereotypeApplications2.add(umlStereotypeApplication); EPackage ePackage = eClass.getEPackage(); Resource eResource = ePackage.eResource(); if (eResource != null) { // converter.addImportedResource(eResource); // -- leads to CCEs for the wrong ES2AS } } private void computeAppliedProfile2profileClosure() { // // Determine the closure of all profiles for each actually applied profile. // for (@SuppressWarnings("null")@NonNull Profile asProfile : appliedProfiles) { Set<Profile> asProfiles = new HashSet<Profile>(); computeProfileClosure(asProfiles, asProfile); appliedProfile2appliedProfileClosure.put(asProfile, asProfiles); } } /** * Update element2elementExtension with an ElementExtension for each of the stereotypeApplications. */ private void computeExplicitElementExtensions(@NonNull Map<Element, Map<Stereotype, ElementExtension>> element2stereotype2extension, @NonNull Map<EObject, List<org.eclipse.uml2.uml.Element>> umlStereotypeApplication2umlStereotypedElements, @NonNull Map<Element, @NonNull List<EObject>> asElement2umlStereotypeApplications) { PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager(); for (@SuppressWarnings("null")@NonNull Element asStereotypedElement : asElement2umlStereotypeApplications.keySet()) { List<EObject> umlStereotypeApplications = asElement2umlStereotypeApplications.get(asStereotypedElement); assert umlStereotypeApplications != null; Map<Stereotype, ElementExtension> stereotype2extension = element2stereotype2extension.get(asStereotypedElement); if (stereotype2extension == null) { stereotype2extension = new HashMap<Stereotype, ElementExtension>(); element2stereotype2extension.put(asStereotypedElement, stereotype2extension); } for (@SuppressWarnings("null")@NonNull EObject umlStereotypeApplication : umlStereotypeApplications) { // EClass eClass = umlStereotypeApplication.eClass(); List<org.eclipse.uml2.uml.Element> umlStereotypedElements = umlStereotypeApplication2umlStereotypedElements.get(umlStereotypeApplication); assert umlStereotypedElements != null; Stereotype asStereotype = converter.resolveStereotype(umlStereotypeApplication, umlStereotypedElements); if (asStereotype == null) { asStereotype = converter.resolveStereotype(umlStereotypeApplication, umlStereotypedElements); // FIXME debugging } if (asStereotype != null) { ElementExtension elementExtension = metamodelManager.getElementExtension(asStereotypedElement, asStereotype); converter.setOriginalMapping(elementExtension, umlStereotypeApplication); elementExtension.setIsApplied(true); stereotype2extension.put(asStereotype, elementExtension); if (UML2AS.ADD_ELEMENT_EXTENSION.isActive()) { UML2AS.ADD_ELEMENT_EXTENSION.println(elementExtension.toString()); } } } } } /** * Update element2elementExtension with an ElementExtension for each of the required ExtensionEnds for each of * the profile applied to each of the packages using package2allProfiles to identiofuy the packages and their * applied profiles and profile2requiredExtensionEnds to idenmtiofy the required ExtensionEnds for each profile. * private void computeImplicitElementExtensions(@NonNull Map<Element, List<ElementExtension>> element2elementExtension, @NonNull Map<org.eclipse.ocl.pivot.Package, Set<Profile>> package2allProfiles, @NonNull Map<org.eclipse.uml2.uml.Profile, List<ExtensionEnd>> profile2requiredExtensionEnds) { for (org.eclipse.ocl.pivot.Package asPackage : package2allProfiles.keySet()) { Set<Profile> asPackageProfiles = package2allProfiles.get(asPackage); for (Profile asProfile : asPackageProfiles) { org.eclipse.uml2.uml.Profile umlProfile = (org.eclipse.uml2.uml.Profile) asProfile.getETarget(); List<org.eclipse.uml2.uml.ExtensionEnd> requiredExtensionEnds = profile2requiredExtensionEnds.get(umlProfile); if (requiredExtensionEnds != null) { for (org.eclipse.uml2.uml.ExtensionEnd umlExtensionEnd : requiredExtensionEnds) { if (umlExtensionEnd != null) { org.eclipse.uml2.uml.Type umlStereotype = umlExtensionEnd.getType(); if (umlStereotype != null) { Stereotype asStereotype = converter.getCreated(Stereotype.class, umlStereotype); if (asStereotype != null) { org.eclipse.uml2.uml.Property umlOtherEnd = umlExtensionEnd.getOtherEnd(); if (umlOtherEnd != null) { org.eclipse.uml2.uml.Type umlStereotypedElement = umlOtherEnd.getType(); if (umlStereotypedElement != null) { try { Type asStereotypedElement = metamodelManager.getPivotOf(Type.class, umlStereotypedElement); if (asStereotypedElement != null) { ElementExtension asElementExtension = metamodelManager.getElementExtension(asStereotypedElement, asStereotype); // setOriginalMapping(asElementExtension, umlStereotype); asElementExtension.setIsApplied(true); List<ElementExtension> asElementExtensions = element2elementExtension.get(asStereotypedElement); if (asElementExtensions == null) { asElementExtensions = new ArrayList<ElementExtension>(); element2elementExtension.put(asStereotypedElement, asElementExtensions); } asElementExtensions.add(asElementExtension); if (UML2AS.ADD_ELEMENT_EXTENSION.isActive()) { UML2AS.ADD_ELEMENT_EXTENSION.println(asElementExtension.toString()); } } } catch (ParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } } } } } } } */ private void computePackage2AppliedProfileClosure() { // // Create the closure of all profiles to each package for which any profile is applied // for (ProfileApplication asProfileApplication : asProfileApplications) { org.eclipse.ocl.pivot.Package asPackage = asProfileApplication.getOwningPackage(); if (asPackage != null) { Profile asProfile = asProfileApplication.getAppliedProfile(); if (asProfile != null) { Set<Profile> appliedProfileClosure1 = appliedProfile2appliedProfileClosure.get(asProfile); if (appliedProfileClosure1 != null) { Set<Profile> appliedProfileClosure2 = package2appliedProfileClosure.get(asPackage); if (appliedProfileClosure2 == null) { appliedProfileClosure2 = new HashSet<Profile>(); package2appliedProfileClosure.put(asPackage, appliedProfileClosure2); } appliedProfileClosure2.addAll(appliedProfileClosure1); } } } } } private void computeProfileClosure(@NonNull Set<Profile> allProfiles, @NonNull Profile asProfile) { if (allProfiles.add(asProfile)) { for (org.eclipse.ocl.pivot.Package asNestedPackage : asProfile.getOwnedPackages()) { if (asNestedPackage instanceof Profile) { computeProfileClosure(allProfiles, (Profile) asNestedPackage); } } for (org.eclipse.ocl.pivot.Package asImportedPackage : asProfile.getImportedPackages()) { if (asImportedPackage instanceof Profile) { computeProfileClosure(allProfiles, (Profile) asImportedPackage); } } } } /** * Install implicit ElementExtensions for all the required ExtensionEnds in all the applied Profiles to the all the packages, * and explicit ElementsExtenmsions for all the applied Stereotype applications. * @param umlStereotypeApplications */ private void installElementExtensionPropertyValues(@NonNull Map<Element, @NonNull Map<Stereotype, ElementExtension>> element2stereotype2extension, @NonNull Map<EObject, @NonNull List<org.eclipse.uml2.uml.Element>> umlStereotypeApplication2umlStereotypedElements) { // // Compute the list of UML stereotype application for each stereotyped pivot element. // Map<Element, @NonNull List<EObject>> asElement2umlStereotypeApplications = resolveStereotypeApplications(umlStereotypeApplication2umlStereotypedElements); // // Compute and install the ElementExtensions from required ExtensionEnds and Stereotype applications // // Map<Element, List<ElementExtension>> element2elementExtension = new HashMap<Element, List<ElementExtension>>(); // Map<org.eclipse.uml2.uml.Profile, List<ExtensionEnd>> profile2requiredExtensionEnds2 = profile2requiredExtensionEnds; // if (profile2requiredExtensionEnds2 != null) { // computeImplicitElementExtensions(element2elementExtension, package2allProfiles, profile2requiredExtensionEnds2); // } // // Compute an explicit ElementExtension for each stereotype application. // computeExplicitElementExtensions(element2stereotype2extension, umlStereotypeApplication2umlStereotypedElements, asElement2umlStereotypeApplications); // // Install all the ElementExtensions // for (@SuppressWarnings("null")@NonNull Element asElement : element2stereotype2extension.keySet()) { Map<Stereotype, ElementExtension> stereotype2extension = element2stereotype2extension.get(asElement); assert stereotype2extension != null; List<ElementExtension> newElementExtensions = new ArrayList<ElementExtension>(stereotype2extension.values()); List<ElementExtension> oldElementExtensions = asElement.getOwnedExtensions(); converter.refreshList(oldElementExtensions, newElementExtensions); } /* if (UML2AS.ADD_ELEMENT_EXTENSION.isActive()) { StringBuffer s = new StringBuffer(); List<Element> asElements = new ArrayList<Element>(element2elementExtension.keySet()); Collections.sort(asElements, ElementComparator.INSTANCE); for (@SuppressWarnings("null")@NonNull Element asElement : asElements) { s.append("\n\t" + EcoreUtils.qualifiedNameFor(asElement)); s.append(" " + ClassUtil.debugSimpleName(asElement)); org.eclipse.ocl.pivot.Package asPackage = PivotUtil.getContainingPackage(asElement); if (asPackage != null) { s.append(" - " + asPackage.getNsURI()); } for (ElementExtension asElementExtension : asElement.getExtensions()) { s.append("\n\t\t" + asElementExtension); s.append(" " + ClassUtil.debugSimpleName(asElementExtension)); } } UML2AS.ADD_ELEMENT_EXTENSION.println("Extensions per Type" + s.toString()); } */ } public void installStereotypes() { profileAnalysis.analyze(); computeAppliedProfile2profileClosure(); computePackage2AppliedProfileClosure(); //// @SuppressWarnings("null")@NonNull Set<Profile> appliedProfileClosure = package2appliedProfileClosure.get(asPackage); // Map<Type, Set<TypeExtension>> metatype2typeExtensions = profileAnalysis.computeMetatypes2typeExtensions(/*appliedProfileClosure*/); // Map<Element, Map<Stereotype, ElementExtension>> element2stereotype2extension = new HashMap<Element, Map<Stereotype, ElementExtension>>(); // for (org.eclipse.ocl.pivot.Package asPackage : package2appliedProfileClosure.keySet()) { // if ((asPackage != null) /*&& !(asPackage instanceof Profile)*/) { Map<Element, @NonNull Map<Stereotype, ElementExtension>> element2stereotype2extension = new HashMap<Element, @NonNull Map<Stereotype, ElementExtension>>(); for (org.eclipse.ocl.pivot.Package asPackage : package2appliedProfileClosure.keySet()) { if ((asPackage != null) && !(asPackage instanceof Profile)) { Set<Profile> appliedProfileClosure = package2appliedProfileClosure.get(asPackage); assert appliedProfileClosure != null; Map<Type, Set<StereotypeExtender>> metatype2typeExtensions = profileAnalysis.computeMetatypes2typeExtensions(appliedProfileClosure); printMetatypes2StereotypeExtensions(asPackage, metatype2typeExtensions); for (TreeIterator<EObject> tit = asPackage.eAllContents(); tit.hasNext(); ) { EObject eObject = tit.next(); if (eObject instanceof Element) { Element asElement = (Element)eObject; EClass eClass = asElement.eClass(); Type metatype = eClass2metatype.get(eClass); if ((metatype == null) && !eClass2metatype.containsKey(eClass)) { EPackage ePackage = eClass.getEPackage(); String ePackageName = ePackage.getName(); String eClassName = eClass.getName(); if ((ePackageName != null) && (eClassName != null)) { metatype = profileAnalysis.getMetatype(ePackageName, eClassName); eClass2metatype.put(eClass, metatype); } } if (metatype != null) { Set<StereotypeExtender> typeExtensions = metatype2typeExtensions.get(metatype); if (typeExtensions != null) { Map<Stereotype, ElementExtension> stereotype2extension = installExtensions(asElement, typeExtensions); element2stereotype2extension.put(asElement, stereotype2extension); } } } } } } List<EObject> umlStereotypeApplications2 = umlStereotypeApplications; if (umlStereotypeApplications2 != null) { Map<EObject, @NonNull List<org.eclipse.uml2.uml.Element>> umlStereotypeApplication2umlStereotypedElements = UML2ASUtil.computeAppliedStereotypes(umlStereotypeApplications2); installElementExtensionPropertyValues(element2stereotype2extension, umlStereotypeApplication2umlStereotypedElements); } // Map<Metaclass<?>, List<Property>> metaclass2properties = new HashMap<Metaclass<?>, List<Property>>(); // // Install all the metaclass properties. // // for (Metaclass<?> metaclass : metaclass2properties.keySet()) { // List<Property> newProperties = metaclass2properties.get(metaclass); // List<Property> oldProperties = metaclass.getOwnedAttribute(); // assert oldProperties != null; // refreshList(oldProperties, newProperties); // } } private @NonNull Map<Stereotype, ElementExtension> installExtensions(@NonNull Element asElement, @NonNull Set<StereotypeExtender> typeExtensions) { PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager(); Map<Stereotype, ElementExtension> stereotype2extension = new HashMap<Stereotype, ElementExtension>(); for (StereotypeExtender typeExtension : typeExtensions) { Stereotype stereotype = typeExtension.getOwningStereotype(); if (stereotype != null) { ElementExtension elementExtension = metamodelManager.getElementExtension(asElement, stereotype); elementExtension.setIsRequired(true); stereotype2extension.put(stereotype, elementExtension); if (UML2AS.ADD_ELEMENT_EXTENSION.isActive()) { UML2AS.ADD_ELEMENT_EXTENSION.println(asElement.toString() + " + " + elementExtension.toString()); } } } return stereotype2extension; } protected void printMetatypes2StereotypeExtensions(org.eclipse.ocl.pivot.@NonNull Package asPackage, @NonNull Map<Type, @NonNull Set<StereotypeExtender>> metatype2typeExtensions) { if (UML2AS.TYPE_EXTENSIONS.isActive()) { StringBuffer s = new StringBuffer(); s.append(NameUtil.qualifiedNameFor(asPackage) + " : " + asPackage.getURI()); List<Type> metatypes = new ArrayList<Type>(metatype2typeExtensions.keySet()); Collections.sort(metatypes, NameUtil.NAMEABLE_COMPARATOR); for (Type metatype : metatypes) { if (metatype != null) { s.append("\n\t" + NameUtil.qualifiedNameFor(metatype) + " ++"); //+ " : " + asProfile.getNsURI()); Set<StereotypeExtender> typeExtensions = metatype2typeExtensions.get(metatype); assert typeExtensions != null; List<Stereotype> stereotypes = new ArrayList<Stereotype>(); for (StereotypeExtender typeExtension : typeExtensions) { stereotypes.add(typeExtension.getOwningStereotype()); } Collections.sort(stereotypes, NameUtil.NAMEABLE_COMPARATOR); for (Stereotype stereotype : stereotypes) { if (stereotype != null) { s.append(" " + NameUtil.qualifiedNameFor(stereotype) + ","); //+ " : " + asProfile.getNsURI()); } } } } UML2AS.TYPE_EXTENSIONS.println(s.toString()); } } /** * Determine the UML stereotype applications for each stereotyped pivot element, from the pre-computed mapping * of stereotyped UML elements for each UML stereotype application. * @param umlStereotypeApplications */ private @NonNull Map<Element, @NonNull List<EObject>> resolveStereotypeApplications(@NonNull Map<EObject, @NonNull List<org.eclipse.uml2.uml.Element>> umlStereotypeApplication2umlStereotypedElements) { Map<Element, @NonNull List<EObject>> asElement2umlStereotypeApplications = new HashMap<Element, @NonNull List<EObject>>(); for (@SuppressWarnings("null")@NonNull EObject umlStereotypeApplication : umlStereotypeApplication2umlStereotypedElements.keySet()) { List<org.eclipse.uml2.uml.Element> umlStereotypedElements = umlStereotypeApplication2umlStereotypedElements.get(umlStereotypeApplication); assert umlStereotypedElements != null; for (@SuppressWarnings("null")org.eclipse.uml2.uml.@NonNull Element umlStereotypedElement : umlStereotypedElements) { Element asStereotypedElement = converter.getCreated(Element.class, umlStereotypedElement); if (asStereotypedElement != null) { List<EObject> umlPerElementStereotypeApplications = asElement2umlStereotypeApplications.get(asStereotypedElement); if (umlPerElementStereotypeApplications == null) { umlPerElementStereotypeApplications = new ArrayList<EObject>(); asElement2umlStereotypeApplications.put(asStereotypedElement, umlPerElementStereotypeApplications); } umlPerElementStereotypeApplications.add(umlStereotypeApplication); } } } return asElement2umlStereotypeApplications; } }