blob: 524f2be4971d082f3490286fbfd7fc0bda4c4887 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2014 EclipseSource Muenchen GmbH 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:
* Philip Langer - initial API and implementation
******************************************************************************/
package org.eclipse.emf.emfstore.internal.modelmutator.mutation;
import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.any;
import static org.eclipse.emf.emfstore.modelmutator.ESModelMutatorUtil.getAllObjectsCount;
import java.util.List;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import com.google.common.base.Predicate;
/**
* A set of predicates used by mutations for selecting, filtering, checking objects and features.
*
* @author Philip Langer
*
*/
public final class MutationPredicates {
private MutationPredicates() {
// hides constructor
}
/** Extended meta data source of EAnnotations. */
public static final String EXTENDED_META_DATA = "http:///org/eclipse/emf/ecore/util/ExtendedMetaData"; //$NON-NLS-1$
/** Key of a details entry in EAnnotations to denote FeatureMap groups. */
public static final String KIND = "kind"; //$NON-NLS-1$
/** Value of a details entry in EAnnotations to denote Feature Map groups. */
public static final String GROUP = "group"; //$NON-NLS-1$
/**
* Predicate specifying whether an {@link EStructuralFeature} is a {@link EReference}.
*/
public static final Predicate<? super EStructuralFeature> IS_REFERENCE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null && input instanceof EReference;
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is a containment {@link EReference}.
*/
public static final Predicate<? super EStructuralFeature> IS_CONTAINMENT_REFERENCE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return IS_REFERENCE.apply(input)
&& ((EReference) input).isContainment();
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is a containment {@link EReference} or the opposite of
* a containment {@link EReference}.
*/
public static final Predicate<? super EStructuralFeature> IS_CONTAINMENT_OR_OPPOSITE_OF_CONTAINMENT_REFERENCE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return IS_CONTAINMENT_REFERENCE.apply(input) || IS_OPPOSITE_OF_CONTAINMENT_REFERENCE.apply(input);
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is the opposite of a containment {@link EReference}.
*/
public static final Predicate<? super EStructuralFeature> IS_OPPOSITE_OF_CONTAINMENT_REFERENCE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null
&& input instanceof EReference
&& ((EReference) input).getEOpposite() != null
&& ((EReference) input).getEOpposite().isContainment();
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is a mutable containment {@link EReference}.
*/
public static final Predicate<? super EStructuralFeature> IS_MUTABLE_CONTAINMENT_REFERENCE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return IS_MUTABLE.apply(input)
&& IS_CONTAINMENT_REFERENCE.apply(input);
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is mutable.
*/
public static final Predicate<? super EStructuralFeature> IS_MUTABLE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null && input.isChangeable();
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is multi-valued.
*/
public static final Predicate<? super EStructuralFeature> IS_MULTI_VALUED = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null && input.isMany();
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is a mutable {@link EAttribute}.
*/
public static final Predicate<? super EStructuralFeature> IS_MUTABLE_ATTRIBUTE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return IS_MUTABLE.apply(input) && input instanceof EAttribute;
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is a mutable {@link EReference}.
*/
public static final Predicate<? super EStructuralFeature> IS_MUTABLE_REFERENCE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return IS_MUTABLE.apply(input) && input instanceof EReference;
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is of type
* {@link org.eclipse.emf.ecore.change.FeatureMapEntry FeatureMapEntry}.
*/
public static final Predicate<? super EStructuralFeature> HAS_FEATURE_MAP_ENTRY_TYPE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null
&& EcorePackage.eINSTANCE.getEFeatureMapEntry().equals(input.getEType());
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} is the feature map attribute of a feature map group.
*/
public static final Predicate<? super EStructuralFeature> HAS_GROUP_FEATURE_MAP_ENTRY_TYPE = new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return HAS_FEATURE_MAP_ENTRY_TYPE.apply(input)
&& input.getEAnnotation(EXTENDED_META_DATA) != null
&& input.getEAnnotation(EXTENDED_META_DATA).getDetails().get(KIND) != null
&& input.getEAnnotation(EXTENDED_META_DATA).getDetails().get(KIND).equals(GROUP);
}
};
/**
* Predicate specifying whether an {@link EStructuralFeature} may take the given {@code eObject} as value.
*
* @param eObject The {@link EObject} to check.
* @return <code>true</code> if it may take {@code eObject} as value, <code>false</code> otherwise.
*/
public static Predicate<? super EStructuralFeature> mayTakeEObjectAsValue(final EObject eObject) {
return new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
if (input != null && input instanceof EReference) {
final EReference eReference = (EReference) input;
return eReference.getEType().isInstance(eObject);
}
return false;
}
};
}
/**
* Predicate specifying whether an {@link EStructuralFeature} has a compatible type to the given {@code feature}.
*
* @param feature The {@link EStructuralFeature} to check.
* @return <code>true</code> if its type is compatible to the one of {@code feature}, <code>false</code> otherwise.
*/
public static Predicate<? super EStructuralFeature> hasCompatibleType(final EStructuralFeature feature) {
return new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null &&
(input.getEType() == feature.getEType()
|| isSubTypeOf(input.getEType(), feature.getEType()));
}
};
}
private static boolean isSubTypeOf(EClassifier eType, EClassifier eType2) {
if (eType instanceof EClass && eType2 instanceof EClass) {
final EClass eClass1 = (EClass) eType;
final EClass eClass2 = (EClass) eType2;
return eClass2.isSuperTypeOf(eClass1);
}
return false;
}
/**
* Predicate specifying whether an {@link EStructuralFeature} has a compatible type to any of the features' types of
* the given {@code eClass}.
*
* @param eClass The {@link EClass} to check.
* @return <code>true</code> if there is at least one feature in {@code eClass} having a compatible type,
* <code>false</code> otherwise.
*/
public static Predicate<? super EStructuralFeature> isCompatibleWithAnyFeatureOfEClass(final EClass eClass) {
return new Predicate<EStructuralFeature>() {
public boolean apply(EStructuralFeature input) {
return input != null &&
any(eClass.getEStructuralFeatures(), hasCompatibleType(input));
}
};
}
/**
* Predicate specifying whether an {@link EObject} may be contained by the given {@code feature}.
*
* @param feature The {@link EStructuralFeature} to check.
* @return <code>true</code> if it may be contained by {@code feature}, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> mayBeContainedByFeature(final EStructuralFeature feature) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return mayTakeEObjectAsValue(input).apply(feature);
}
};
}
/**
* Predicate specifying whether an {@link EObject} may be contained by any of the given {@code references}.
*
* @param references The references to check.
* @return <code>true</code> if there is at least one reference in {@code references}, which may contain it,
* <code>false</code> otherwise.
*/
public static Predicate<? super EObject> mayBeContainedByAnyOfTheseReferences(
final Iterable<EReference> references) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return input != null && any(references, mayTakeEObjectAsValue(input));
}
};
}
/**
* Predicate specifying whether an {@link EObject} is not the same as the given {@code eObject}.
*
* @param eObject The {@link EObject} to compare it to.
* @return <code>true</code> if it is not the same, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> isNotTheSame(final EObject eObject) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return input != null && input != eObject;
}
};
}
/**
* Predicate specifying whether an {@link EObject} is the child of the given {@code eObject}.
*
* @param eObject The {@link EObject} to check.
* @return <code>true</code> if it is a child of {@code eObject}, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> isChild(final EObject eObject) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return input != null && EcoreUtil.isAncestor(eObject, input);
}
};
}
/**
* Predicate specifying whether an {@link EObject} is the ancestor of a given {@code eObject}.
*
* @param eObject The {@link EObject} to check.
* @return <code>true</code> if it is the ancestor of {@code eObject}, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> isAncestor(final EObject eObject) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return input != null && EcoreUtil.isAncestor(input, eObject);
}
};
}
/**
* Predicate specifying whether an {@link EObject} is contained by the given {@code feature}.
*
* @param feature The {@link EStructuralFeature} to check.
* @return <code>true</code> if it is contained by {@code feature}, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> isContainedByFeature(final EStructuralFeature feature) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return input != null && input.eContainingFeature() == feature;
}
};
}
/**
* Predicate specifying whether an {@link EObject} is contained by the given {@code eContainer}.
*
* @param eContainer The {@link EObject} to check.
* @return <code>true</code> if it is contained by {@code eContainer}, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> isContainedByEObject(final EObject eContainer) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return input != null && input.eContainer() == eContainer;
}
};
}
/**
* Predicate specifying whether an {@link Object} is not <code>null</code> or an empty list.
*/
public static final Predicate<? super Object> IS_NON_EMPTY_VALUE_OR_LIST = new Predicate<Object>() {
public boolean apply(Object input) {
return !(input == null || isEmptyList(input));
}
};
private static boolean isEmptyList(Object input) {
if (input instanceof List<?>) {
final List<?> list = (List<?>) input;
return list.isEmpty();
}
return false;
}
/**
* Predicate specifying whether an {@link Object} is a feature map containing at least one value.
*/
public static final Predicate<? super Object> IS_NON_EMPTY_FEATURE_MAP = new Predicate<Object>() {
public boolean apply(Object input) {
return input != null && input instanceof FeatureMap && ((FeatureMap) input).size() > 0;
}
};
/**
* Predicate specifying whether an {@link Object} is an {@link EObject} or a list of {@link EObject EObjects}
* containing at least one EObject.
*/
public static final Predicate<? super Object> IS_NON_EMPTY_EOBJECT_OR_LIST = new Predicate<Object>() {
public boolean apply(Object input) {
return IS_NON_NULL_EOBJECT.apply(input) || IS_NON_EMPTY_EOBJECT_LIST.apply(input);
}
};
/**
* Predicate specifying whether an {@link Object} is not null and an {@link EObject}.
*/
public static final Predicate<? super Object> IS_NON_NULL_EOBJECT = new Predicate<Object>() {
public boolean apply(Object input) {
return input != null && input instanceof EObject;
}
};
/**
* Predicate specifying whether an {@link Object} is a list of {@link EObject EObjects} containing at least one
* EObject.
*/
public static final Predicate<? super Object> IS_NON_EMPTY_EOBJECT_LIST = new Predicate<Object>() {
public boolean apply(Object input) {
return input instanceof List<?> && isNonEmptyEObjectList((List<?>) input);
}
};
private static boolean isNonEmptyEObjectList(List<?> input) {
return !input.isEmpty() && all(input, IS_NON_NULL_EOBJECT);
}
/**
* Predicate specifying whether an {@link Object} is <code>null</code> or a list.
*/
public static final Predicate<? super Object> IS_NULL_OR_LIST = new Predicate<Object>() {
public boolean apply(Object input) {
return input == null || IS_LIST.apply(input);
}
};
/**
* Predicate specifying whether an {@link Object} is a list.
*/
public static final Predicate<? super Object> IS_LIST = new Predicate<Object>() {
public boolean apply(Object input) {
return input instanceof List<?>;
}
};
/**
* Predicate specifying whether an {@link Object} is the container of an {@link EObject} that itself has at most the
* given number of {@code maxNumberOfContainments}.
*
* @param maxNumberOfContainments The maximum number of containments to check.
* @return <code>true</code> if it contains an {@link EObject} that itself has a less or equal number of
* containments than specified in {@code maxNumberOfContainments}, <code>false</code> otherwise.
*/
public static Predicate<? super Object> containsEObjectWithMaxNumberOfContainments(
final int maxNumberOfContainments) {
return new Predicate<Object>() {
public boolean apply(Object input) {
return input != null
&& or(isListContainingEObjectWithMaxNumberOfContainments(maxNumberOfContainments),
isEObjectWithMaxNumberOfContainments(maxNumberOfContainments)).apply(input);
}
};
}
/**
* Predicate specifying whether an {@link Object} is a list of {@link EObject EObjects} containing one EObject
* that itself has at most the given number of {@code maxNumberOfContainments}.
*
* @param maxNumberOfContainments The maximum number of containments to check.
* @return <code>true</code> if it is a list containing an {@link EObject} that itself has a less or equal number of
* containments than specified in {@code maxNumberOfContainments}, <code>false</code> otherwise.
*/
public static Predicate<? super Object> isListContainingEObjectWithMaxNumberOfContainments(
final int maxNumberOfContainments) {
return new Predicate<Object>() {
@SuppressWarnings("unchecked")
public boolean apply(Object input) {
return input instanceof List<?>
&& any((List<EObject>) input, hasMaxNumberOfContainments(maxNumberOfContainments));
}
};
}
/**
* Predicate specifying whether an {@link Object} is an {@link EObject} containing at most the given number of
* {@code maxNumberOfContainments}.
*
* @param maxNumberOfContainments The maximum number of containments to check.
* @return <code>true</code> if it is is an {@link EObject} containing a less or equal number of
* containments than specified in {@code maxNumberOfContainments}, <code>false</code> otherwise.
*/
public static Predicate<? super Object> isEObjectWithMaxNumberOfContainments(final int maxNumberOfContainments) {
return new Predicate<Object>() {
public boolean apply(Object input) {
return input instanceof EObject
&& hasMaxNumberOfContainments(maxNumberOfContainments).apply((EObject) input);
}
};
}
/**
* Predicate specifying whether an {@link EObject} contains at most the given number of
* {@code maxNumberOfContainments}.
*
* @param maxNumberOfContainments The maximum number of containments to check.
* @return <code>true</code> if it contains a less or equal number of containments than specified in
* {@code maxNumberOfContainments}, <code>false</code> otherwise.
*/
public static Predicate<? super EObject> hasMaxNumberOfContainments(final int maxNumberOfContainments) {
return new Predicate<EObject>() {
public boolean apply(EObject input) {
return getAllObjectsCount(input) <= maxNumberOfContainments;
}
};
}
/**
* Predicate specifying whether an {@link Object} is a list with the given {@code size}.
*
* @param size The size to check.
* @return <code>true</code> if it is a list of the given {@code size}, <code>false</code> otherwise.
*/
public static Predicate<? super Object> isListWithSpecifiedSize(final int size) {
return new Predicate<Object>() {
public boolean apply(Object originalValue) {
if (originalValue instanceof List<?>) {
final List<?> originalValueList = (List<?>) originalValue;
return originalValueList.size() == size;
}
return false;
}
};
}
}