blob: aad892589a040a52bad1ccb0cb2ce36a9f980441 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2015 Willink Transformations Ltd., University of York 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:
* Adolfo Sanchez-Barbudo Herrera (University of York) - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.pivot.lookup;
import java.util.Collection;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.internal.lookup.LookupEnvironment;
import org.eclipse.ocl.pivot.internal.lookup.impl.LookupEnvironmentImpl;
/**
* @since 1.1
*/
public class SingleResultLookupEnvironment extends LookupEnvironmentImpl implements SingleResultEnvironment {
private static final Logger logger = Logger.getLogger(SingleResultLookupEnvironment.class);
private @NonNull String name;
private @NonNull Executor executor;
public SingleResultLookupEnvironment(@NonNull Executor executor, @NonNull String name) {
this.executor = executor;
this.name = name;
//this.envFactory = executor.getEnvironmentFactory();
}
public SingleResultLookupEnvironment(@NonNull Executor executor, @NonNull String name, Boolean isLocal) {
this(executor, name);
}
@Override
@NonNull
public LookupEnvironment addElement(@Nullable NamedElement namedElement) {
if (namedElement != null) {
if (name.equals(namedElement.getName())) {
List<NamedElement> elements = getNamedElements();
if (!elements.contains(namedElement)) {
elements.add(namedElement);
}
}
}
return this;
}
@Override
@NonNull
public <NE extends NamedElement> LookupEnvironment addElements(
@Nullable Collection<NE> elements) {
if (elements != null) {
for (NamedElement namedElement : elements) {
addElement(namedElement);
}
}
return this;
}
@Override
@Nullable
public NamedElement getSingleResult() {
List<NamedElement> elements = getNamedElements();
int contentsSize = elements.size();
if (contentsSize > 1) {
logger.warn("Unhandled ambiguous content for '" + name + "'");
}
return contentsSize == 0 ? null : elements.get(0);
}
@SuppressWarnings("null")
@Override
@NonNull
public List<NamedElement> getAllResults() {
return getNamedElements();
}
@Override
public boolean hasFinalResult() {
// Not thing found is not a final result
return getNamedElements().size() == 0 ? false : true;
}
@Override
@NonNull
public Executor getExecutor() {
return executor;
}
/*
//
// ADDITIONAL STUFF TO INTEGRATE WITH
//
public static abstract class Disambiguator<T> implements Comparator<T>
{
@Override
public int compare(T o1, T o2) {
throw new UnsupportedOperationException();
}
public abstract int compare(@NonNull EnvironmentFactory environmentFactory, @NonNull T o1, @NonNull T o2);
}
private static final class ImplicitDisambiguator extends Disambiguator<Object>
{
@Override
public int compare(@NonNull EnvironmentFactory environmentFactory, @NonNull Object match1, @NonNull Object match2) {
boolean match1IsImplicit = (match1 instanceof Property) && ((Property)match1).isIsImplicit();
boolean match2IsImplicit = (match2 instanceof Property) && ((Property)match2).isIsImplicit();
if (!match1IsImplicit) {
return match2IsImplicit ? 1 : 0; // match2 inferior
}
else {
return match2IsImplicit ? 0 : -1; // match1 inferior
}
}
}
private static final class MetamodelMergeDisambiguator extends Disambiguator<Feature>
{
@Override
public int compare(@NonNull EnvironmentFactory environmentFactory, @NonNull Feature match1, @NonNull Feature match2) {
org.eclipse.ocl.pivot.Package p1 = PivotUtil.getContainingPackage(match1);
org.eclipse.ocl.pivot.Package p2 = PivotUtil.getContainingPackage(match2);
if (p1 == null) {
return 0;
}
if (p2 == null) {
return 0;
}
CompleteModel completeModel = environmentFactory.getCompleteModel();
CompletePackage s1 = completeModel.getCompletePackage(p1);
CompletePackage s2 = completeModel.getCompletePackage(p2);
if (s1 != s2) {
return 0;
}
int i1 = s1.getIndex(p1);
int i2 = s2.getIndex(p2);
return i2 - i1;
}
}
private static final class OperationDisambiguator extends Disambiguator<Operation>
{
@Override
public int compare(@NonNull EnvironmentFactory environmentFactory, @NonNull Operation match1, @NonNull Operation match2) {
if (isRedefinitionOf(match1, match2)) {
return 1; // match2 inferior
}
if (isRedefinitionOf(match2, match1)) {
return -1; // match1 inferior
}
return 0;
}
protected boolean isRedefinitionOf(@NonNull Operation operation1, @NonNull Operation operation2) {
List<Operation> redefinedOperations = operation1.getRedefinedOperations();
for (Operation redefinedOperation : redefinedOperations) {
if (redefinedOperation != null) {
if (redefinedOperation == operation2) {
return true;
}
if (isRedefinitionOf(redefinedOperation, operation2)) {
return true;
}
}
}
return false;
}
}
private static final class MergedPackageDisambiguator extends Disambiguator<org.eclipse.ocl.pivot.Package>
{
@Override
public int compare(@NonNull EnvironmentFactory environmentFactory, org.eclipse.ocl.pivot.@NonNull Package match1, org.eclipse.ocl.pivot.@NonNull Package match2) {
CompleteModel completeModel = environmentFactory.getCompleteModel();
CompletePackage completePackage1 = completeModel.getCompletePackage(match1);
CompletePackage completePackage2 = completeModel.getCompletePackage(match2);
if (completePackage1 == completePackage2) {
return 1; // match2 inferior
}
return 0;
}
}
private static final class PropertyDisambiguator extends Disambiguator<Property>
{
@Override
public int compare(@NonNull EnvironmentFactory environmentFactory, @NonNull Property match1, @NonNull Property match2) {
if (isRedefinitionOf(match1, match2)) {
return 1; // match2 inferior
}
if (isRedefinitionOf(match2, match1)) {
return -1; // match1 inferior
}
return 0;
}
protected boolean isRedefinitionOf(@NonNull Property property1, @NonNull Property property2) {
List<Property> redefinedProperties = property1.getRedefinedProperties();
for (Property redefinedProperty : redefinedProperties) {
if (redefinedProperty != null) {
if (redefinedProperty == property2) {
return true;
}
if (isRedefinitionOf(redefinedProperty, property2)) {
return true;
}
}
}
return false;
}
}
private static @NonNull LinkedHashMap<Class<?>, List<Comparator<Object>>> disambiguatorMap = // FIXME narrow API to Disambiguator
new LinkedHashMap<Class<?>, List<Comparator<Object>>>();
static {
addDisambiguator(Object.class, new ImplicitDisambiguator());
addDisambiguator(Feature.class, new MetamodelMergeDisambiguator());
addDisambiguator(Operation.class, new OperationDisambiguator());
addDisambiguator(org.eclipse.ocl.pivot.Package.class, new MergedPackageDisambiguator());
addDisambiguator(Property.class, new PropertyDisambiguator());
}
public static synchronized <T> void addDisambiguator(@NonNull Class<T> targetClass, @NonNull Comparator<T> disambiguator) {
List<Comparator<Object>> disambiguators = disambiguatorMap.get(targetClass);
if (disambiguators == null) {
disambiguators = new ArrayList<Comparator<Object>>();
disambiguatorMap.put(targetClass, disambiguators);
}
@SuppressWarnings("unchecked")
Comparator<Object> castDisambiguator = (Comparator<Object>) disambiguator;
disambiguators.add(castDisambiguator);
}
@SuppressWarnings("null")
public static @NonNull Iterable<Class<?>> getDisambiguatorKeys() {
return disambiguatorMap.keySet();
}
public static @Nullable List<Comparator<Object>> getDisambiguators(@NonNull Class<?> key) {
return disambiguatorMap.get(key);
}
protected final @NonNull EnvironmentFactory envFactory;
private List<ScopeFilter> matchers = null; // Prevailing filters for matching
private Set<ScopeFilter> resolvers = null; // Successful filters for resolving
public void addFilter(@NonNull ScopeFilter filter) {
if (matchers == null) {
matchers = new ArrayList<ScopeFilter>();
}
matchers.add(filter);
}
public void removeFilter(@NonNull ScopeFilter filter) {
if (matchers != null) {
matchers.remove(filter);
}
}
@NonNull
public SingleResultLookupEnvironment resolveDuplicates() {
if (elements.size() > 1) {
// FIXME this WAS done while "adding" elements. Adding here where they are supposed
// to be used. Talk with ED about this.
if (matchers != null) {
if (resolvers == null) {
resolvers = new HashSet<ScopeFilter>();
}
resolvers.addAll(matchers);
}
for (int i = 0; i < elements.size()-1;) {
boolean iRemoved = false;
@SuppressWarnings("null") @NonNull Object iValue = elements.get(i);
for (int j = i + 1; j < elements.size();) {
Class<?> iClass = iValue.getClass();
@SuppressWarnings("null") @NonNull Object jValue = elements.get(j);
Class<?> jClass = jValue.getClass();
int verdict = 0;
for (Class<?> key : disambiguatorMap.keySet()) {
if (key.isAssignableFrom(iClass) && key.isAssignableFrom(jClass)) {
for (Comparator<Object> comparator : disambiguatorMap.get(key)) {
if (comparator instanceof Disambiguator<?>) {
verdict = ((Disambiguator<Object>)comparator).compare(envFactory, iValue, jValue);
} else {
verdict = comparator.compare(iValue, jValue);
}
if (verdict != 0) {
break;
}
}
if (verdict != 0) {
break;
}
}
}
if (verdict == 0) {
j++;
} else if (verdict < 0) {
elements.remove(i);
iRemoved = true;
break;
} else {
elements.remove(j);
}
}
if (!iRemoved) {
i++;
}
}
}
return this;
}
*/
}