/******************************************************************************* * Copyright (c) 2011, 2015 Willink Transformations 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 - Initial API and implementation *******************************************************************************/ package org.eclipse.ocl.pivot.internal.library.executor; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.ocl.pivot.CompleteInheritance; import org.eclipse.ocl.pivot.InheritanceFragment; import org.eclipse.ocl.pivot.Operation; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; import org.eclipse.ocl.pivot.library.LibraryFeature; import org.eclipse.ocl.pivot.library.oclany.OclAnyUnsupportedOperation; import org.eclipse.ocl.pivot.types.AbstractFragment; /** * A ReflectiveFragment provides the description of the properties and operations defined by some class when accessed by the same * or another class. The descriptions are normally built lazily and one name at a time using reflective access to some meta-model. */ public abstract class ReflectiveFragment extends AbstractFragment { protected Map<Operation, LibraryFeature> operationMap = null; protected Map<Operation, Operation> apparentOperation2actualOperation = null; protected Map<Property, LibraryFeature> propertyMap = null; public ReflectiveFragment(@NonNull CompleteInheritance derivedInheritance, @NonNull CompleteInheritance baseInheritance) { super(derivedInheritance, baseInheritance); } @Override public @NonNull LibraryFeature getImplementation(@NonNull Operation apparentOperation) { if (operationMap == null) { synchronized (this) { if (operationMap == null) { operationMap = new HashMap<Operation, LibraryFeature>(); // Optimize to reuse single super map if no local ops } } } LibraryFeature libraryFeature = operationMap.get(apparentOperation); if (libraryFeature != null) { return libraryFeature; } synchronized (operationMap) { libraryFeature = operationMap.get(apparentOperation); if (libraryFeature != null) { return libraryFeature; } Operation localOperation = getLocalOperation(apparentOperation); if (localOperation == null) { if (derivedInheritance == baseInheritance) { localOperation = apparentOperation; } } if (localOperation != null) { // Trivial case, there is a local operation libraryFeature = PivotUtilInternal.getImplementation(localOperation); } else { // Non-trivial, search up the inheritance tree for an inherited operation Operation bestOverload = null; CompleteInheritance bestInheritance = null; int bestDepth = -1; int minDepth = baseInheritance.getDepth(); for (int depth = derivedInheritance.getDepth()-1; depth >= minDepth; depth--) { Iterable<InheritanceFragment> derivedSuperFragments = derivedInheritance.getSuperFragments(depth); for (InheritanceFragment derivedSuperFragment : derivedSuperFragments) { CompleteInheritance superInheritance = derivedSuperFragment.getBaseInheritance(); InheritanceFragment superFragment = superInheritance.getFragment(baseInheritance); if (superFragment != null) { Operation overload = superFragment.getLocalOperation(apparentOperation); if (overload != null) { if (bestInheritance == null) { // First candidate bestDepth = depth; bestInheritance = superInheritance; bestOverload = overload; } else if (depth == bestDepth) { // Sibling candidate bestOverload = null; depth = -1; break; } else if (!bestInheritance.isSubInheritanceOf(superInheritance)) { // Non-occluded child candidate bestOverload = null; depth = -1; break; } } } } } if (bestOverload != null) { libraryFeature = PivotUtilInternal.getImplementation(bestOverload); } else { libraryFeature = OclAnyUnsupportedOperation.AMBIGUOUS; } } if (libraryFeature == null) { libraryFeature = OclAnyUnsupportedOperation.INSTANCE; } operationMap.put(apparentOperation, libraryFeature); return libraryFeature; } } @Override public @NonNull Iterable<? extends Operation> getLocalOperations() { return operationMap != null ? operationMap.keySet() : Collections.<Operation>emptyList(); } @Override public @NonNull Iterable<? extends Property> getLocalProperties() { return propertyMap != null ? propertyMap.keySet() : Collections.<Property>emptyList(); } }