| /******************************************************************************* |
| * Copyright (c) 2014, 2019 Willink Transformations and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * E.D.Willink - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ocl.pivot.internal.complete; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EFactory; |
| import org.eclipse.emf.ecore.util.EObjectResolvingEList; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.pivot.Behavior; |
| import org.eclipse.ocl.pivot.Class; |
| import org.eclipse.ocl.pivot.CompleteClass; |
| import org.eclipse.ocl.pivot.CompleteInheritance; |
| import org.eclipse.ocl.pivot.CompletePackage; |
| import org.eclipse.ocl.pivot.Element; |
| import org.eclipse.ocl.pivot.ElementExtension; |
| import org.eclipse.ocl.pivot.InheritanceFragment; |
| import org.eclipse.ocl.pivot.Operation; |
| import org.eclipse.ocl.pivot.Package; |
| import org.eclipse.ocl.pivot.PivotFactory; |
| import org.eclipse.ocl.pivot.PivotPackage; |
| import org.eclipse.ocl.pivot.Property; |
| import org.eclipse.ocl.pivot.Region; |
| import org.eclipse.ocl.pivot.State; |
| import org.eclipse.ocl.pivot.StateMachine; |
| import org.eclipse.ocl.pivot.Stereotype; |
| import org.eclipse.ocl.pivot.StereotypeExtender; |
| import org.eclipse.ocl.pivot.TemplateBinding; |
| import org.eclipse.ocl.pivot.TemplateParameter; |
| import org.eclipse.ocl.pivot.TemplateParameterSubstitution; |
| import org.eclipse.ocl.pivot.TemplateParameters; |
| import org.eclipse.ocl.pivot.TemplateSignature; |
| import org.eclipse.ocl.pivot.Type; |
| import org.eclipse.ocl.pivot.Vertex; |
| import org.eclipse.ocl.pivot.ids.IdResolver.IdResolverExtension; |
| import org.eclipse.ocl.pivot.ids.OperationId; |
| import org.eclipse.ocl.pivot.ids.PackageId; |
| import org.eclipse.ocl.pivot.ids.ParametersId; |
| import org.eclipse.ocl.pivot.internal.ClassImpl; |
| import org.eclipse.ocl.pivot.internal.CompleteClassImpl; |
| import org.eclipse.ocl.pivot.internal.manager.Orphanage; |
| import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; |
| import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; |
| import org.eclipse.ocl.pivot.util.DerivedConstants; |
| import org.eclipse.ocl.pivot.util.PivotPlugin; |
| import org.eclipse.ocl.pivot.utilities.ClassUtil; |
| import org.eclipse.ocl.pivot.utilities.FeatureFilter; |
| import org.eclipse.ocl.pivot.utilities.NameUtil; |
| import org.eclipse.ocl.pivot.utilities.PivotUtil; |
| import org.eclipse.ocl.pivot.utilities.TracingOption; |
| import org.eclipse.ocl.pivot.utilities.TypeUtil; |
| |
| import com.google.common.base.Function; |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Iterables; |
| |
| public class PartialClasses extends EObjectResolvingEList<org.eclipse.ocl.pivot.Class> implements ClassListeners.IClassListener |
| { |
| private static final long serialVersionUID = 1L; |
| public static final @NonNull TracingOption PARTIAL_CLASSES = new TracingOption(PivotPlugin.PLUGIN_ID, "partialClasses"); |
| // static { PARTIAL_CLASSES.setState(true); } |
| |
| public static final @NonNull TracingOption ADD_BASE_PROPERTY = new TracingOption(PivotPlugin.PLUGIN_ID, "partialClasses/addBaseProperty"); |
| public static final @NonNull TracingOption ADD_EXTENSION_PROPERTY = new TracingOption(PivotPlugin.PLUGIN_ID, "partialClasses/addExtensionProperty"); |
| public static final @NonNull TracingOption INIT_MEMBER_OPERATIONS = new TracingOption(PivotPlugin.PLUGIN_ID, "partialClasses/initMemberOperations"); |
| public static final @NonNull TracingOption INIT_MEMBER_PROPERTIES = new TracingOption(PivotPlugin.PLUGIN_ID, "partialClasses/initMemberProperties"); |
| |
| /* protected static class QualifiedName2DomainInheritance implements Function<String, DomainInheritance> |
| { |
| protected final @NonNull Map<String, DomainInheritance> name2superclasses; |
| |
| protected QualifiedName2DomainInheritance(@NonNull Map<String, DomainInheritance> name2superclasses) { |
| this.name2superclasses = name2superclasses; |
| } |
| |
| public DomainInheritance apply(String qualifiedClassName) { |
| return name2superclasses.get(qualifiedClassName); |
| } |
| } */ |
| |
| /** |
| * Lazily created map from operation name to map of parameter types to the list of partial operations to be treated as merged. |
| */ |
| private @Nullable Map<@NonNull String, @NonNull PartialOperations> name2partialOperations = null; |
| |
| /** |
| * Lazily created map from property name to the list of properties to be treated as merged. |
| */ |
| private @Nullable Map<@NonNull String, @NonNull PartialProperties> name2partialProperties = null; |
| |
| private Set<@NonNull CompleteClassInternal> superCompleteClasses = null; |
| |
| /** |
| * Lazily created map from class name to the superclass. This is a map from unqualified name to |
| * class for the normal case when all superclass names are distinct. However if any two superclasses |
| * including this class share a name, all superclasses are mapped by qualified name, and the |
| * name2qualifiedNames provides an additional mapping of the ambiguities. |
| */ |
| // private @Nullable Map<String, DomainInheritance> name2superclasses = null; // FIXME duplicates superCompleteClasses |
| |
| /** |
| * Lazily created map from class name to the list of qualified names for same-named super-classes. |
| * This list is only non-null if a class has two same-named superclasses that need disambiguation.. |
| */ |
| // private @Nullable Map<String, List<String>> name2qualifiedNames = null; |
| |
| /** |
| * Lazily created map from state name to the known state. |
| */ |
| private @Nullable Map<@NonNull String, @NonNull State> name2states = null; |
| |
| protected /*@NonNull*/ CompleteInheritanceImpl completeInheritance; |
| |
| /** |
| * Map from actual types to specialization. |
| * <br> |
| * The specializations are weakly referenced so that stale specializations are garbage collected. |
| */ |
| // FIXME tests fail if keys are weak since GC is too aggressive across tests |
| // The actual types are weak keys so that parameterizations using stale types are garbage collected. |
| // |
| private @Nullable /*WeakHash*/Map<TemplateParameters, WeakReference<org.eclipse.ocl.pivot.Class>> specializations = null; |
| |
| public PartialClasses(@NonNull CompleteClassImpl completeClass) { |
| super(org.eclipse.ocl.pivot.Class.class, completeClass, PivotPackage.Literals.COMPLETE_CLASS__PARTIAL_CLASSES.getFeatureID()); |
| } |
| |
| @Override |
| public void addUnique(org.eclipse.ocl.pivot.Class partialClass) { |
| assert partialClass != null; |
| didAdd(partialClass); |
| super.addUnique(partialClass); |
| } |
| |
| @Override |
| public void addUnique(int index, org.eclipse.ocl.pivot.Class partialClass) { |
| assert partialClass != null; |
| didAdd(partialClass); |
| super.addUnique(index, partialClass); |
| } |
| |
| public @NonNull Set<@NonNull CompleteClassInternal> computeSuperCompleteClasses() { |
| Set<@NonNull CompleteClassInternal> superCompleteClasses2 = superCompleteClasses; |
| if (superCompleteClasses2 == null) { |
| CompleteModelInternal completeModel = getCompleteModel(); |
| superCompleteClasses2 = superCompleteClasses = new HashSet<@NonNull CompleteClassInternal>(); |
| for (org.eclipse.ocl.pivot.Class partialClass : this) { |
| for (org.eclipse.ocl.pivot.@NonNull Class partialSuperClass : ClassUtil.nullFree(partialClass.getSuperClasses())) { |
| CompleteClassInternal superCompleteClass = completeModel.getCompleteClass(PivotUtil.getUnspecializedTemplateableElement(partialSuperClass)); |
| superCompleteClasses2.add(superCompleteClass); |
| superCompleteClasses2.addAll(superCompleteClass.getPartialClasses().computeSuperCompleteClasses()); |
| } |
| } |
| if (superCompleteClasses2.isEmpty()) { |
| CompleteClassInternal oclAnyCompleteClass = completeModel.getCompleteClass(completeModel.getStandardLibrary().getOclAnyType()); |
| if (getCompleteClass() != oclAnyCompleteClass) { |
| superCompleteClasses2.add(oclAnyCompleteClass); |
| } |
| } |
| } |
| return superCompleteClasses2; |
| } |
| |
| protected @NonNull Property createExtensionProperty(@NonNull ElementExtension stereotypeInstance, org.eclipse.ocl.pivot.@NonNull Class baseType) { |
| Stereotype stereotype = stereotypeInstance.getStereotype(); |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| assert name2partialProperties2 != null; |
| String extensionPropertyName = DerivedConstants.STEREOTYPE_EXTENSION_PREFIX + stereotype.getName(); |
| Property extensionProperty = null; |
| PartialProperties partialProperties = name2partialProperties2.get(extensionPropertyName); |
| if (partialProperties == null) { |
| partialProperties = new PartialProperties(getEnvironmentFactory()); |
| name2partialProperties2.put(extensionPropertyName, partialProperties); |
| } |
| for (@NonNull Property partialProperty : partialProperties) { |
| extensionProperty = partialProperty; |
| break; |
| } |
| if (extensionProperty == null) { |
| extensionProperty = PivotFactory.eINSTANCE.createProperty(); |
| extensionProperty.setName(extensionPropertyName); |
| baseType.getOwnedProperties().add(extensionProperty); |
| } |
| extensionProperty.setType(stereotype); |
| boolean isRequired = false; |
| for (StereotypeExtender typeExtension : stereotype.getOwnedExtenders()) { |
| Type metatype = typeExtension.getClass_(); |
| if ((metatype != null) && baseType.conformsTo(getStandardLibrary(), metatype)) { |
| isRequired = true; |
| break; |
| } |
| } |
| extensionProperty.setIsRequired(isRequired); |
| extensionProperty.setIsStatic(false); |
| return extensionProperty; |
| } |
| |
| protected org.eclipse.ocl.pivot.@NonNull Class createSpecialization(@NonNull TemplateParameters templateArguments) { |
| org.eclipse.ocl.pivot.Class unspecializedType = getCompleteClass().getPrimaryClass(); |
| String typeName = unspecializedType.getName(); |
| TemplateSignature templateSignature = unspecializedType.getOwnedSignature(); |
| List<TemplateParameter> templateParameters = templateSignature.getOwnedParameters(); |
| EClass eClass = unspecializedType.eClass(); |
| EFactory eFactoryInstance = eClass.getEPackage().getEFactoryInstance(); |
| org.eclipse.ocl.pivot.Class specializedType = (org.eclipse.ocl.pivot.Class) eFactoryInstance.create(eClass); |
| specializedType.setName(typeName); |
| TemplateBinding templateBinding = PivotFactory.eINSTANCE.createTemplateBinding(); |
| for (int i = 0; i < templateParameters.size(); i++) { |
| TemplateParameter formalParameter = templateParameters.get(i); |
| if (formalParameter != null) { |
| Element templateArgument = templateArguments.get(i); |
| if (templateArgument instanceof Type) { |
| Type actualType = (Type) templateArgument; |
| TemplateParameterSubstitution templateParameterSubstitution = CompleteInheritanceImpl.createTemplateParameterSubstitution(formalParameter, actualType); |
| templateBinding.getOwnedSubstitutions().add(templateParameterSubstitution); |
| } |
| } |
| } |
| specializedType.getOwnedBindings().add(templateBinding); |
| getCompleteModel().resolveSuperClasses(specializedType, unspecializedType); |
| // if (specializedType instanceof Metaclass) { |
| // Type instanceType = (Type) templateArguments.get(0); |
| // Metaclass specializedMetaclass = (Metaclass)specializedType; |
| // specializedMetaclass.setInstanceType(instanceType); |
| // } |
| specializedType.setUnspecializedElement(unspecializedType); |
| PivotMetamodelManager metamodelManager = getCompleteModel().getMetamodelManager(); |
| Orphanage orphanage = Orphanage.getOrphanage(metamodelManager.getASResourceSet()); |
| specializedType.setOwningPackage(orphanage); |
| return specializedType; |
| } |
| |
| protected void didAdd(org.eclipse.ocl.pivot.Class partialClass) { |
| if (PARTIAL_CLASSES.isActive()) { |
| PARTIAL_CLASSES.println("Do-didAdd " + this + " " + partialClass); |
| } |
| ((ClassImpl)partialClass).addClassListener(this); |
| if (partialClass.getUnspecializedElement() == null) { |
| getCompleteModel().didAddClass(partialClass, getCompleteClass()); |
| } |
| // if (name2partialProperties != null) { |
| // doRefreshPartialProperties(partialClass); |
| // } |
| // if (name2partialOperations != null) { |
| // doRefreshPartialOperations(partialClass); |
| // } |
| dispose(); // Force lazy recomputation |
| } |
| |
| @Override |
| protected void didRemove(int index, org.eclipse.ocl.pivot.Class partialClass) { |
| assert partialClass != null; |
| if (PARTIAL_CLASSES.isActive()) { |
| PARTIAL_CLASSES.println("Do-didRemove " + this + " " + partialClass); |
| } |
| super.didRemove(index, partialClass); |
| ((ClassImpl)partialClass).removeClassListener(this); |
| dispose(); // Force lazy recomputation |
| } |
| |
| @Override |
| public void didAddOperation(@NonNull Operation pivotOperation) { |
| Map<String, PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 != null) { |
| String operationName = pivotOperation.getName(); |
| if (operationName != null) { |
| PartialOperations partialOperations = name2partialOperations2.get(operationName); |
| if (partialOperations == null) { |
| partialOperations = new PartialOperations(getCompleteClass(), operationName); |
| name2partialOperations2.put(operationName, partialOperations); |
| } |
| partialOperations.didAddOperation(pivotOperation); |
| } |
| } |
| } |
| |
| @Override |
| public void didAddProperty(@NonNull Property pivotProperty) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 != null) { |
| String propertyName = pivotProperty.getName(); |
| PartialProperties partials = name2partialProperties2.get(propertyName); |
| if (partials == null) { |
| partials = new PartialProperties(getEnvironmentFactory()); |
| name2partialProperties2.put(propertyName, partials); |
| } |
| partials.didAddProperty(pivotProperty); |
| } |
| } |
| |
| @Override |
| public void didAddSuperClass(org.eclipse.ocl.pivot.@NonNull Class partialClass) { |
| if (completeInheritance != null) { |
| completeInheritance.uninstall(); |
| } |
| } |
| |
| @Override |
| public void didRemoveOperation(@NonNull Operation pivotOperation) { |
| Map<String, PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 != null) { |
| String operationName = pivotOperation.getName(); |
| PartialOperations partialOperations = name2partialOperations2.get(operationName); |
| if (partialOperations != null) { |
| if (partialOperations.didRemoveOperation(pivotOperation)) { |
| name2partialOperations2.remove(operationName); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void didRemoveProperty(@NonNull Property pivotProperty) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 != null) { |
| String propertyName = pivotProperty.getName(); |
| PartialProperties partials = name2partialProperties2.get(propertyName); |
| if (partials != null) { |
| if (partials.didRemoveProperty(pivotProperty)) { |
| name2partialProperties2.remove(propertyName); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void didRemoveSuperClass(org.eclipse.ocl.pivot.@NonNull Class partialClass) { |
| if (completeInheritance != null) { |
| completeInheritance.uninstall(); |
| } |
| } |
| |
| public void dispose() { |
| CompleteClassInternal completeClass = getCompleteClass(); |
| CompletePackageInternal owningCompletePackage = completeClass.getOwningCompletePackage(); |
| if (owningCompletePackage != null) { |
| owningCompletePackage.getPartialPackages().uninstalled(completeClass); |
| } |
| completeInheritance = null; |
| Map<String, PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 != null) { |
| name2partialOperations2.clear(); |
| name2partialOperations = null; |
| } |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 != null) { |
| name2partialProperties2.clear(); |
| name2partialProperties = null; |
| } |
| // name2superclasses = null; |
| superCompleteClasses = null; |
| } |
| |
| public synchronized @Nullable Type findSpecializedType(@NonNull TemplateParameters templateArguments) { |
| TemplateSignature templateSignature = getCompleteClass().getPrimaryClass().getOwnedSignature(); |
| List<TemplateParameter> templateParameters = templateSignature.getOwnedParameters(); |
| int iMax = templateParameters.size(); |
| if (templateArguments.parametersSize() != iMax) { |
| return null; |
| } |
| Map<TemplateParameters, WeakReference<org.eclipse.ocl.pivot.Class>> specializations2 = specializations; |
| if (specializations2 == null) { |
| return null; |
| } |
| WeakReference<org.eclipse.ocl.pivot.Class> weakReference = specializations2.get(templateArguments); |
| if (weakReference == null) { |
| return null; |
| } |
| org.eclipse.ocl.pivot.Class type = weakReference.get(); |
| if (type == null) { |
| synchronized (specializations2) { |
| type = weakReference.get(); |
| if (type == null) { |
| specializations2.remove(templateArguments); |
| } |
| } |
| } |
| return type; |
| } |
| |
| private void gatherAllStereotypes(@NonNull Set<Stereotype> allStereotypes, @NonNull Iterable<Stereotype> moreStereotypes) { |
| Set<Stereotype> newStereotypes = null; |
| PivotMetamodelManager metamodelManager = getMetamodelManager(); |
| for (@SuppressWarnings("null")@NonNull Stereotype stereotype : moreStereotypes) { |
| stereotype = metamodelManager.getPrimaryElement(stereotype); |
| if (allStereotypes.add(stereotype)) { |
| CompleteClass superCompleteClass = null; |
| if (stereotype instanceof CompleteInheritanceImpl) { |
| superCompleteClass = ((CompleteInheritanceImpl)stereotype).getCompleteClass(); |
| } |
| else { |
| superCompleteClass = getCompleteModel().getCompleteClass(stereotype); |
| } |
| if (newStereotypes == null) { |
| newStereotypes = new HashSet<Stereotype>(); |
| } |
| for (org.eclipse.ocl.pivot.Class partialType : superCompleteClass.getPartialClasses()) { |
| if (partialType instanceof Stereotype) { |
| Stereotype partialStereotype = (Stereotype) partialType; |
| newStereotypes.add(partialStereotype); |
| for (org.eclipse.ocl.pivot.Class superType : partialStereotype.getSuperClasses()) { |
| if (superType instanceof Stereotype) { |
| Stereotype superStereotype = (Stereotype)superType; |
| superType = metamodelManager.getPrimaryElement(superStereotype); |
| newStereotypes.add(superStereotype); |
| } |
| } |
| } |
| } |
| } |
| } |
| if (newStereotypes != null) { |
| gatherAllStereotypes(allStereotypes, newStereotypes); |
| } |
| } |
| |
| @SuppressWarnings("null") |
| public @NonNull CompleteClassInternal getCompleteClass() { |
| return (CompleteClassImpl) owner; |
| } |
| |
| public final @NonNull CompleteInheritanceImpl getCompleteInheritance() { |
| CompleteInheritanceImpl completeInheritance2 = completeInheritance; |
| if (completeInheritance2 == null) { |
| CompleteClassInternal completeClass = getCompleteClass(); |
| CompletePackageInternal completePackage = completeClass.getOwningCompletePackage(); |
| completeInheritance2 = completePackage.getCompleteInheritance(completeClass); |
| completeInheritance = completeInheritance2; |
| } |
| return completeInheritance2; |
| } |
| |
| public @NonNull CompleteModelInternal getCompleteModel() { |
| return getCompleteClass().getCompleteModel(); |
| } |
| |
| public @NonNull EnvironmentFactoryInternal getEnvironmentFactory() { |
| return getCompleteClass().getEnvironmentFactory(); |
| } |
| |
| public @NonNull Iterable<@NonNull ? extends CompleteInheritance> getInitialSuperInheritances() { |
| final @NonNull Iterator<@NonNull CompleteClassInternal> iterator = ClassUtil.nonNull(computeSuperCompleteClasses().iterator()); // FIXME Use local cache |
| return new Iterable<@NonNull CompleteInheritance>() |
| { |
| @Override |
| public @NonNull Iterator<@NonNull CompleteInheritance> iterator() { |
| return new Iterator<@NonNull CompleteInheritance>() |
| { |
| @Override |
| public boolean hasNext() { |
| return iterator.hasNext(); |
| } |
| |
| @Override |
| public @NonNull CompleteInheritance next() { |
| CompleteClassInternal next = ClassUtil.nonNull(iterator.next()); |
| return next.getCompleteInheritance(); |
| } |
| |
| @Override |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| } |
| }; |
| } |
| |
| public @NonNull PivotMetamodelManager getMetamodelManager() { |
| return getCompleteClass().getMetamodelManager(); |
| } |
| |
| public @Nullable Operation getOperation(@NonNull OperationId operationId) { |
| Map<String, PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| String operationName = operationId.getName(); |
| PartialOperations partialOperations = name2partialOperations2.get(operationName); |
| if (partialOperations == null) { |
| return null; |
| } |
| return partialOperations.getOperation(operationId.getParametersId(), null); |
| } |
| |
| public @Nullable Operation getOperation(@NonNull Operation pivotOperation) { |
| Map<String, PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| String operationName = pivotOperation.getName(); |
| PartialOperations partialOperations = name2partialOperations2.get(operationName); |
| if (partialOperations == null) { |
| return null; |
| } |
| return partialOperations.getOperation(pivotOperation.getParametersId(), pivotOperation.isIsStatic() ? FeatureFilter.SELECT_STATIC : FeatureFilter.SELECT_NON_STATIC); |
| } |
| |
| public @NonNull Iterable<String> getOperationNames() { |
| Map<String, PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| return name2partialOperations2.keySet(); |
| } |
| |
| public @Nullable Iterable<@NonNull Operation> getOperationOverloads(@NonNull Operation pivotOperation) { |
| Map<@NonNull String, @NonNull PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| String operationName = pivotOperation.getName(); |
| PartialOperations partialOperations = name2partialOperations2.get(operationName); |
| if (partialOperations == null) { |
| return null; |
| } |
| ParametersId parametersId = pivotOperation.getParametersId(); |
| return partialOperations.getOperationOverloads(parametersId, pivotOperation.isIsStatic() ? FeatureFilter.SELECT_STATIC : FeatureFilter.SELECT_NON_STATIC); |
| } |
| |
| public @NonNull Iterable<@NonNull Operation> getOperationOverloads(final @Nullable FeatureFilter featureFilter, @Nullable String name) { |
| Map<@NonNull String, @NonNull PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| PartialOperations partialOperations = name2partialOperations2.get(name); |
| if (partialOperations == null) { |
| return PivotMetamodelManager.EMPTY_OPERATION_LIST; |
| } |
| return partialOperations.getOperationOverloads(featureFilter); |
| } |
| |
| public @NonNull Iterable<@NonNull Operation> getOperations() { |
| Map<@NonNull String, @NonNull PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| Iterable<Iterable<Iterable<@NonNull Operation>>> transformed = Iterables.transform(name2partialOperations2.values(), PartialOperations.partialOperations2allOperations); |
| @NonNull Iterable<@NonNull Operation> concat = Iterables.concat(Iterables.concat(transformed)); |
| return concat; |
| } |
| |
| public @NonNull Iterable<@NonNull Operation> getOperations(final @Nullable FeatureFilter featureFilter) { |
| Map<@NonNull String, @NonNull PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = initMemberOperations(); |
| } |
| Iterable<@NonNull PartialOperations> itMapListOps = name2partialOperations2.values(); |
| @NonNull Iterable<Iterable<Iterable<@NonNull Operation>>> itItListOps = Iterables.transform(itMapListOps, PartialOperations.partialOperations2allOperations); |
| @NonNull Iterable<Iterable<@NonNull Operation>> itListOps = Iterables.concat(itItListOps); |
| @NonNull Iterable<@NonNull Operation> itOps = Iterables.concat(itListOps); |
| if (featureFilter == null) { |
| return itOps; |
| } |
| @NonNull Iterable<@NonNull Operation> subItOps = Iterables.filter(itOps, |
| new Predicate<@NonNull Operation>() |
| { |
| @Override |
| public boolean apply(@NonNull Operation domainOperation) { |
| return featureFilter.accept(domainOperation); |
| } |
| }); |
| return subItOps; |
| } |
| |
| public @NonNull Iterable<@NonNull Property> getProperties(final @Nullable FeatureFilter featureFilter) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 == null) { |
| name2partialProperties2 = initMemberProperties(); |
| } |
| List<@NonNull Property> properties = new ArrayList<@NonNull Property>(); |
| for (@NonNull PartialProperties partialProperties : name2partialProperties2.values()) { |
| @Nullable Property property = partialProperties.get(); |
| if (property != null) { |
| if (featureFilter == null) { |
| properties.add(property); |
| } |
| else if (featureFilter.accept(property)) { |
| properties.add(property); |
| } |
| } |
| } |
| return properties; |
| } |
| |
| public @NonNull Iterable<@NonNull Property> getProperties(final @Nullable FeatureFilter featureFilter, @Nullable String name) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 == null) { |
| name2partialProperties2 = initMemberProperties(); |
| } |
| PartialProperties partials = name2partialProperties2.get(name); |
| if ((partials == null) || partials.isEmpty()) { |
| return PivotMetamodelManager.EMPTY_PROPERTY_LIST; |
| } |
| // @SuppressWarnings("null") |
| // @NonNull List<DomainProperty> singletonList = partials; //Collections.singletonList(partials.get(0)); |
| if (featureFilter == null) { |
| return partials; |
| } |
| @NonNull Iterable<@NonNull Property> subItOps = Iterables.filter(partials, |
| new Predicate<@NonNull Property>() |
| { |
| @Override |
| public boolean apply(@NonNull Property domainProperty) { |
| return featureFilter.accept(domainProperty); |
| } |
| }); |
| return subItOps; |
| } |
| |
| public @Nullable Iterable<@NonNull Property> getProperties(@NonNull Property pivotProperty) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 == null) { |
| name2partialProperties2 = initMemberProperties(); |
| } |
| String propertyName = pivotProperty.getName(); |
| return name2partialProperties2.get(propertyName); |
| } |
| |
| public @Nullable Iterable<@NonNull Property> getProperties(@Nullable String propertyName) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 == null) { |
| name2partialProperties2 = initMemberProperties(); |
| } |
| return name2partialProperties2.get(propertyName); |
| } |
| |
| public @Nullable Property getProperty(@Nullable String propertyName) { |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 == null) { |
| name2partialProperties2 = initMemberProperties(); |
| } |
| PartialProperties partials = name2partialProperties2.get(propertyName); |
| if (partials == null) { |
| return null; |
| } |
| return partials.get(); |
| } |
| |
| public synchronized org.eclipse.ocl.pivot.@NonNull Class getSpecializedType(@NonNull List<@NonNull ? extends Type> templateArguments) { |
| return getSpecializedType(TypeUtil.createTemplateParameters(templateArguments)); |
| } |
| |
| public synchronized org.eclipse.ocl.pivot.@NonNull Class getSpecializedType(@NonNull TemplateParameters templateArguments) { |
| TemplateSignature templateSignature = getCompleteClass().getPrimaryClass().getOwnedSignature(); |
| List<TemplateParameter> templateParameters = templateSignature.getOwnedParameters(); |
| int iMax = templateParameters.size(); |
| if (templateArguments.parametersSize() != iMax) { |
| throw new IllegalArgumentException("Incompatible template argument count"); |
| } |
| Map<TemplateParameters, WeakReference<org.eclipse.ocl.pivot.Class>> specializations2 = specializations; |
| if (specializations2 == null) { |
| synchronized(this) { |
| specializations2 = specializations; |
| if (specializations2 == null) { |
| specializations2 = specializations = new /*Weak*/HashMap<TemplateParameters, WeakReference<org.eclipse.ocl.pivot.Class>>(); |
| } |
| } |
| } |
| synchronized (specializations2) { |
| org.eclipse.ocl.pivot.Class specializedType = null; |
| WeakReference<org.eclipse.ocl.pivot.Class> weakReference = specializations2.get(templateArguments); |
| if (weakReference != null) { |
| specializedType = weakReference.get(); |
| } |
| if (specializedType == null) { |
| specializedType = createSpecialization(templateArguments); |
| specializations2.put(templateArguments, new WeakReference<org.eclipse.ocl.pivot.Class>(specializedType)); |
| } |
| return specializedType; |
| } |
| } |
| |
| public @NonNull StandardLibraryInternal getStandardLibrary() { |
| return getCompleteModel().getStandardLibrary(); |
| } |
| |
| public @NonNull Iterable<@NonNull State> getStates() { |
| Map<@NonNull String, @NonNull State> name2states2 = name2states; |
| if (name2states2 == null) { |
| name2states2 = initStates(); |
| } |
| return name2states2.values(); |
| } |
| |
| public @NonNull Iterable<@NonNull State> getStates(@Nullable String name) { |
| Map<@NonNull String, @NonNull State> name2states2 = name2states; |
| if (name2states2 == null) { |
| name2states2 = initStates(); |
| } |
| State state = name2states2.get(name); |
| if (state == null) { |
| return PivotMetamodelManager.EMPTY_STATE_LIST; |
| } |
| else { |
| return Collections.singletonList(state); |
| } |
| } |
| |
| public @NonNull Iterable<@NonNull CompleteClass> getSuperCompleteClasses() { |
| CompleteInheritance inheritance = getCompleteClass().getCompleteInheritance(); |
| return Iterables.transform(inheritance.getAllSuperFragments(), new Function<InheritanceFragment, @NonNull CompleteClass>() |
| { |
| @Override |
| public @NonNull CompleteClass apply(InheritanceFragment input) { |
| return ((CompleteInheritanceImpl)input.getBaseInheritance()).getCompleteClass(); |
| } |
| }); |
| } |
| |
| protected void initExtensionPropertiesFrom(org.eclipse.ocl.pivot.@NonNull Class baseType, @NonNull Stereotype stereotype) { |
| PivotMetamodelManager metamodelManager = getMetamodelManager(); |
| ElementExtension elementExtension = metamodelManager.getElementExtension(baseType, stereotype); |
| Map<String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| assert name2partialProperties2 != null; |
| |
| Property extensionProperty = createExtensionProperty(elementExtension, baseType); |
| didAddProperty(extensionProperty); |
| if (ADD_EXTENSION_PROPERTY.isActive()) { |
| ADD_EXTENSION_PROPERTY.println(NameUtil.qualifiedNameFor(extensionProperty) + " => " + NameUtil.qualifiedNameFor(extensionProperty.getType())); |
| } |
| } |
| |
| public void initMemberFeaturesFrom(org.eclipse.ocl.pivot.@NonNull Class pivotType) { |
| if (name2partialOperations != null) { |
| initMemberOperationsFrom(pivotType); |
| } |
| if (name2partialProperties != null) { |
| initMemberPropertiesFrom(pivotType); // FIXME invalidate is safer |
| } |
| } |
| |
| private @NonNull Map<@NonNull String, @NonNull PartialOperations> initMemberOperations() { |
| Map<@NonNull String, @NonNull PartialOperations> name2partialOperations2 = name2partialOperations; |
| if (name2partialOperations2 == null) { |
| name2partialOperations2 = name2partialOperations = new HashMap<@NonNull String, @NonNull PartialOperations>(); |
| // Set<CompleteClass> allSuperCompleteClasses = new HashSet<CompleteClass>(); |
| // allSuperCompleteClasses.add(completeClass); |
| // for (CompleteClass superCompleteClass : completeClass.getSuperCompleteClasses()) { |
| // allSuperCompleteClasses.add(superCompleteClass); |
| // } |
| for (@NonNull CompleteClass superCompleteClass : getSuperCompleteClasses()) { |
| for (org.eclipse.ocl.pivot.@NonNull Class superType : ClassUtil.nullFree(superCompleteClass.getPartialClasses())) { |
| org.eclipse.ocl.pivot.Class unspecializedType = PivotUtil.getUnspecializedTemplateableElement(superType); |
| CompleteClass unspecializedCompleteClass = getCompleteModel().getCompleteClass(unspecializedType); |
| for (org.eclipse.ocl.pivot.@NonNull Class unspecializedPartialType : ClassUtil.nullFree(unspecializedCompleteClass.getPartialClasses())) { |
| assert unspecializedPartialType != null; |
| initMemberOperationsFrom(unspecializedPartialType); |
| } |
| } |
| } |
| for (PartialOperations partialOperations : name2partialOperations2.values()) { |
| partialOperations.initMemberOperationsPostProcess(); |
| } |
| } |
| return name2partialOperations2; |
| } |
| |
| private void initMemberOperationsFrom(org.eclipse.ocl.pivot.@NonNull Class type) { |
| if (INIT_MEMBER_OPERATIONS.isActive()) { |
| INIT_MEMBER_OPERATIONS.println(this + " from " + type); |
| } |
| for (@SuppressWarnings("null")@NonNull Operation pivotOperation : type.getOwnedOperations()) { |
| if (pivotOperation.getName() != null) { // name may be null for partially initialized Complete OCL document. |
| didAddOperation(pivotOperation); |
| } |
| } |
| } |
| |
| protected @NonNull Map<String, @NonNull PartialProperties> initMemberProperties() { |
| Map<@NonNull String, @NonNull PartialProperties> name2partialProperties2 = name2partialProperties; |
| if (name2partialProperties2 == null) { |
| name2partialProperties2 = name2partialProperties = new HashMap<@NonNull String, @NonNull PartialProperties>(); |
| List<@NonNull ElementExtension> allExtensions = null; |
| Set<@NonNull Stereotype> extendingStereotypes = null; |
| Set<@NonNull Type> extendedTypes = null; |
| for (@NonNull CompleteClass superCompleteClass : getSuperCompleteClasses()) { |
| for (org.eclipse.ocl.pivot.@NonNull Class superType : ClassUtil.nullFree(superCompleteClass.getPartialClasses())) { |
| org.eclipse.ocl.pivot.Class unspecializedType = PivotUtil.getUnspecializedTemplateableElement(superType); |
| List<StereotypeExtender> extendedBys = unspecializedType.getExtenders(); |
| if (extendedBys.size() > 0) { |
| if (extendingStereotypes == null) { |
| extendingStereotypes = new HashSet<@NonNull Stereotype>(); |
| } |
| for (@NonNull StereotypeExtender typeExtension : ClassUtil.nullFree(extendedBys)) { |
| Stereotype stereotype = typeExtension.getOwningStereotype(); |
| if (stereotype != null) { |
| extendingStereotypes.add(stereotype); |
| } |
| } |
| } |
| if (unspecializedType instanceof Stereotype) { |
| List<@NonNull StereotypeExtender> extensionOfs = ClassUtil.nullFree(((Stereotype)unspecializedType).getOwnedExtenders()); |
| if (extensionOfs.size() > 0) { |
| if (extendedTypes == null) { |
| extendedTypes = new HashSet<@NonNull Type>(); |
| } |
| for (@NonNull StereotypeExtender typeExtension : extensionOfs) { |
| Type type = typeExtension.getClass_(); |
| if (type != null) { |
| extendedTypes.add(type); |
| } |
| } |
| } |
| } |
| CompleteClass unspecializedCompleteClass = getCompleteModel().getCompleteClass(unspecializedType); |
| for (org.eclipse.ocl.pivot.@NonNull Class unspecializedPartialType : ClassUtil.nullFree(unspecializedCompleteClass.getPartialClasses())) { |
| initMemberPropertiesFrom(unspecializedPartialType); |
| List<@NonNull ElementExtension> extensions = ClassUtil.nullFree(unspecializedPartialType.getOwnedExtensions()); |
| if (extensions.size() > 0) { |
| if (allExtensions == null) { |
| allExtensions = new ArrayList<@NonNull ElementExtension>(); |
| } |
| allExtensions.addAll(extensions); |
| } |
| } |
| } |
| } |
| Class pivotClass = getCompleteClass().getPrimaryClass(); |
| if (INIT_MEMBER_PROPERTIES.isActive()) { |
| INIT_MEMBER_PROPERTIES.println(this + " for " + pivotClass + " " + NameUtil.debugSimpleName(pivotClass)); |
| } |
| if (extendingStereotypes != null) { |
| Set<@NonNull Stereotype> allStereotypes = new HashSet<@NonNull Stereotype>(); |
| gatherAllStereotypes(allStereotypes, extendingStereotypes); |
| for (@NonNull Stereotype stereotype : allStereotypes) { |
| org.eclipse.ocl.pivot.@NonNull Class baseType = pivotClass; |
| initExtensionPropertiesFrom(baseType, stereotype); |
| } |
| } |
| @SuppressWarnings("null")@NonNull String metatypeName = pivotClass.eClass().getName(); |
| CompletePackageInternal rootCompletePackage = getCompleteClass().getOwningCompletePackage().getRootCompletePackage(); |
| Package pivotPackage = rootCompletePackage.getPrimaryPackage(); |
| if (pivotPackage != null) { |
| EnvironmentFactoryInternal environmentFactory = getEnvironmentFactory(); |
| PackageId metapackageId = environmentFactory.getTechnology().getMetapackageId(environmentFactory, pivotPackage); |
| org.eclipse.ocl.pivot.Package metapackage = ((IdResolverExtension)environmentFactory.getIdResolver()).basicGetPackage(metapackageId); |
| if (metapackage != null) { |
| CompletePackage metaCompletePackage = getMetamodelManager().getCompletePackage(metapackage); |
| Type metatype = metaCompletePackage.getType(metatypeName); |
| if (metatype != null) { |
| CompleteClass metaCompleteClass = getCompleteModel().getCompleteClass(metatype); |
| for (@NonNull Property property : metaCompleteClass.getProperties(FeatureFilter.SELECT_EXTENSION)) { |
| didAddProperty(property); // FIXME Clone the M2 property to have the correct M1 container/type |
| } |
| } |
| } |
| } |
| for (@NonNull PartialProperties properties : name2partialProperties2.values()) { |
| initMemberPropertiesPostProcess(getCompleteClass().getName(), properties); |
| } |
| } |
| return name2partialProperties2; |
| } |
| |
| protected void initMemberPropertiesFrom(org.eclipse.ocl.pivot.@NonNull Class asType) { |
| org.eclipse.ocl.pivot.Class asPrimaryType = PivotUtil.getUnspecializedTemplateableElement(asType); |
| if (INIT_MEMBER_PROPERTIES.isActive()) { |
| INIT_MEMBER_PROPERTIES.println(this + " from " + asPrimaryType + " " + NameUtil.debugSimpleName(asPrimaryType)); |
| } |
| for (ElementExtension extension : asPrimaryType.getOwnedExtensions()) { |
| assert extension != null; |
| // initStereotypePropertiesFrom((Type)asPrimaryType, extension); |
| } |
| for (@SuppressWarnings("null")@NonNull Property pivotProperty : asPrimaryType.getOwnedProperties()) { |
| didAddProperty(pivotProperty); |
| } |
| } |
| |
| protected void initMemberPropertiesPostProcess(String name, @NonNull PartialProperties properties) { |
| // TODO Auto-generated method stub // FIXME Prune occlusions |
| } |
| |
| protected @NonNull Map<@NonNull String, @NonNull State> initStates() { |
| Map<@NonNull String, @NonNull State> name2states = new HashMap<@NonNull String, @NonNull State>(); |
| for (@NonNull CompleteClass superCompleteClass : getSuperCompleteClasses()) { |
| for (org.eclipse.ocl.pivot.@NonNull Class superPartialClass : ClassUtil.nullFree(superCompleteClass.getPartialClasses())) { |
| for (@NonNull Behavior behavior : ClassUtil.nullFree(superPartialClass.getOwnedBehaviors())) { |
| if (behavior instanceof StateMachine) { |
| @NonNull List<@NonNull Region> regions = ClassUtil.nullFree(((StateMachine)behavior).getOwnedRegions()); |
| initStatesForRegions(name2states, regions); |
| } |
| } |
| } |
| } |
| return name2states; |
| } |
| protected void initStatesForRegions(@NonNull Map<String, State> name2states, @NonNull List<@NonNull Region> regions) { |
| for (@NonNull Region region : regions) { |
| for (@NonNull Vertex vertex : ClassUtil.nullFree(region.getOwnedSubvertexes())) { |
| if (vertex instanceof State) { |
| State state = (State) vertex; |
| name2states.put(vertex.getName(), state); |
| @NonNull List<@NonNull Region> nestedRegions = ClassUtil.nullFree(state.getOwnedRegions()); |
| initStatesForRegions(name2states, nestedRegions); |
| } |
| } |
| } |
| } |
| |
| /* protected @NonNull Map<String, DomainInheritance> initSuperClasses() { |
| // System.out.println("initSuperClasses " + toString()); |
| Map<String, DomainInheritance> name2superclasses2 = name2superclasses = new HashMap<String, DomainInheritance>(); |
| name2qualifiedNames = null; |
| for (DomainFragment fragment : ((AbstractTypeServer)getTypeServer()).getFragments()) { |
| DomainInheritance baseInheritance = fragment.getBaseInheritance(); |
| String name = baseInheritance.getName(); |
| DomainInheritance oldInheritance = name2superclasses2.put(name, baseInheritance); |
| if (oldInheritance != null) { |
| name2superclasses2.clear(); |
| name2qualifiedNames = initSuperClassesWithAmbiguousNames(name2superclasses2, new HashMap<String, List<String>>()); |
| break; |
| } |
| } |
| return name2superclasses2; |
| } */ |
| |
| /* protected Map<String, List<String>> initSuperClassesWithAmbiguousNames(Map<String, DomainInheritance> name2superclasses2, Map<String, List<String>> name2qualifiedNames2) { |
| int counter = 0; |
| for (DomainFragment fragment : getCompleteClass().getCompleteInheritance().getFragments()) { |
| DomainInheritance baseInheritance = fragment.getBaseInheritance(); |
| String name = baseInheritance.getName(); |
| String qualifiedName = Integer.toString(counter++); |
| name2superclasses2.put(qualifiedName, baseInheritance); |
| List<String> names = name2qualifiedNames2.get(name); |
| if (names == null) { |
| names = new ArrayList<String>(); |
| name2qualifiedNames2.put(name, names); |
| } |
| names.add(name); |
| } |
| return name2qualifiedNames2; |
| } */ |
| } |