blob: 54f3d2ae29e50ce7f1fb402d02ffbf915070fce6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 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.utilities;
import java.util.Map;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.xmi.impl.EMOFExtendedMetaData;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
import org.eclipse.ocl.pivot.values.IntegerValue;
import org.eclipse.ocl.pivot.values.UnlimitedNaturalValue;
/**
* OppositePropertyDetails is a utility class gathering together and eventually unifying the disparate code processing
* the opposite property-related EAnnotations.
*
* @since 1.10
*/
public class OppositePropertyDetails
{
public static final @NonNull String BODY_KEY = EMOFExtendedMetaData.EMOF_COMMENT_BODY;
public static final @NonNull String LOWER_KEY = "lower";
public static final @NonNull String ORDERED_KEY = "ordered";
public static final @NonNull String UNIQUE_KEY = "unique";
public static final @NonNull String UPPER_KEY = "upper";
private static final Logger logger = Logger.getLogger(OppositePropertyDetails.class);
/**
* The key that identifies opposite role names in an annotation
*/
public static final String PROPERTY_OPPOSITE_ROLE_NAME_KEY = "Property.oppositeRoleName"; //$NON-NLS-1$
public static final Object PROPERTY_OPPOSITE_ROLE_UNIQUE_KEY = "Property.oppositeUnique"; //$NON-NLS-1$
public static final Object PROPERTY_OPPOSITE_ROLE_ORDERED_KEY = "Property.oppositeOrdered"; //$NON-NLS-1$
public static final Object PROPERTY_OPPOSITE_ROLE_LOWER_KEY = "Property.oppositeLower"; //$NON-NLS-1$
public static final Object PROPERTY_OPPOSITE_ROLE_UPPER_KEY = "Property.oppositeUpper"; //$NON-NLS-1$
public static @Nullable OppositePropertyDetails createFromEReference(@NonNull EReference eReference) {
EReference eOpposite = eReference.getEOpposite();
if (eOpposite != null) {
String oppositeName = eOpposite.getName();
IntegerValue lower = ValueUtil.integerValueOf(eOpposite.getLowerBound());
UnlimitedNaturalValue upper = ValueUtil.unlimitedNaturalValueOf(eOpposite.getUpperBound());
return new OppositePropertyDetails(oppositeName, eOpposite.isOrdered(), eOpposite.isUnique(), lower, upper);
}
else {
EAnnotation oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PACKAGE_NS_URI_2_0);
if (oppositeRole != null) {
EMap<String, String> details = oppositeRole.getDetails();
String oppositeName = details.get(PROPERTY_OPPOSITE_ROLE_NAME_KEY);
if (oppositeName != null) {
String uniqueValue = details.get(PROPERTY_OPPOSITE_ROLE_UNIQUE_KEY);
String orderedValue = details.get(PROPERTY_OPPOSITE_ROLE_ORDERED_KEY);
String lowerValue = details.get(PROPERTY_OPPOSITE_ROLE_LOWER_KEY);
String upperValue = details.get(PROPERTY_OPPOSITE_ROLE_UPPER_KEY);
boolean isOrdered = orderedValue != null ? Boolean.valueOf(orderedValue) : false;
boolean isUnique = uniqueValue != null ? Boolean.valueOf(uniqueValue) : true;
IntegerValue one = ValueUtil.ONE_VALUE;
IntegerValue lower = lowerValue != null ? ValueUtil.integerValueOf(lowerValue) : one;
if (lower.isInvalid()) {
logger.error("Invalid " + PROPERTY_OPPOSITE_ROLE_LOWER_KEY + " " + lower);
lower = one;
}
UnlimitedNaturalValue unlimitedOne = ValueUtil.UNLIMITED_ONE_VALUE;
UnlimitedNaturalValue upper = upperValue != null ? ValueUtil.unlimitedNaturalValueOf(upperValue) : unlimitedOne;
if (upper.isInvalid()) {
logger.error("Invalid " + PROPERTY_OPPOSITE_ROLE_UPPER_KEY + " " + upper);
upper = unlimitedOne;
}
return new OppositePropertyDetails(oppositeName, isOrdered, isUnique, lower, upper);
}
}
else {
oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PROPERTY_OPPOSITE_ROLE_NAME_ANNOTATION_SOURCE);
if (oppositeRole != null) {
EMap<String, String> details = oppositeRole.getDetails();
String oppositeName = details.get(BODY_KEY);
if (oppositeName != null) {
// EObject eContainer = asProperty.eContainer();
// if (eContainer instanceof Type) {
String uniqueValue = details.get(UNIQUE_KEY);
String orderedValue = details.get(ORDERED_KEY);
String lowerValue = details.get(LOWER_KEY);
String upperValue = details.get(UPPER_KEY);
boolean isOrdered = orderedValue != null ? Boolean.valueOf(orderedValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_ORDERED;
boolean isUnique = uniqueValue != null ? Boolean.valueOf(uniqueValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UNIQUE;
IntegerValue lower = lowerValue != null ? ValueUtil.integerValueOf(lowerValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE;
if (lower.isInvalid()) {
logger.error("Invalid " + PROPERTY_OPPOSITE_ROLE_LOWER_KEY + " " + lower);
lower = PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE;
}
UnlimitedNaturalValue upper = upperValue != null ? ValueUtil.unlimitedNaturalValueOf(upperValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE;
if (upper.isInvalid()) {
logger.error("Invalid " + PROPERTY_OPPOSITE_ROLE_UPPER_KEY + " " + upper);
upper = PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE;
}
return new OppositePropertyDetails(oppositeName, isOrdered, isUnique, lower, upper);
}
}
}
return null;
}
}
/* public static @NonNull OppositePropertyDetails createOppositeEAnnotationDetails(@NonNull EReference eReference) {
String oppositeName;
IntegerValue lower = ValueUtil.ZERO_VALUE;
UnlimitedNaturalValue upper = ValueUtil.unlimitedNaturalValueOf(0);
EReference eOpposite = eReference.getEOpposite();
if (eOpposite != null) {
oppositeName = eOpposite.getName();
lower = ValueUtil.integerValueOf(eOpposite.getLowerBound());
upper = ValueUtil.unlimitedNaturalValueOf(eOpposite.getUpperBound());
}
else {
oppositeName = "«inferred»";
EAnnotation oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PACKAGE_NS_URI_2_0);
if (oppositeRole != null) {
EMap<String, String> details = oppositeRole.getDetails();
oppositeName = details.get(PROPERTY_OPPOSITE_ROLE_NAME_KEY);
if (oppositeName != null) {
String lowerValue = details.get(PROPERTY_OPPOSITE_ROLE_LOWER_KEY);
String upperValue = details.get(PROPERTY_OPPOSITE_ROLE_UPPER_KEY);
IntegerValue one = ValueUtil.ONE_VALUE;
UnlimitedNaturalValue unlimitedOne = ValueUtil.UNLIMITED_ONE_VALUE;
lower = lowerValue != null ? ValueUtil.integerValueOf(lowerValue) : one;
upper = upperValue != null ? ValueUtil.unlimitedNaturalValueOf(upperValue) : unlimitedOne;
if (lower.isInvalid()) {
// logger.error("Invalid " + PropertyDetails.PROPERTY_OPPOSITE_ROLE_LOWER_KEY + " " + lower);
lower = one;
}
if (upper.isInvalid()) {
// logger.error("Invalid " + PropertyDetails.PROPERTY_OPPOSITE_ROLE_UPPER_KEY + " " + upper);
upper = unlimitedOne;
}
}
}
else {
oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PROPERTY_OPPOSITE_ROLE_NAME_ANNOTATION_SOURCE);
if (oppositeRole != null) {
EMap<String, String> details = oppositeRole.getDetails();
oppositeName = details.get(EMOFExtendedMetaData.EMOF_COMMENT_BODY);
if (oppositeName != null) {
String lowerValue = details.get("lower");
String upperValue = details.get("upper");
lower = lowerValue != null ? ValueUtil.integerValueOf(lowerValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE;
upper = upperValue != null ? ValueUtil.unlimitedNaturalValueOf(upperValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE;
if (lower.isInvalid()) {
// logger.error("Invalid " + PropertyDetails.PROPERTY_OPPOSITE_ROLE_LOWER_KEY + " " + lower);
lower = PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE;
}
if (upper.isInvalid()) {
// logger.error("Invalid " + PropertyDetails.PROPERTY_OPPOSITE_ROLE_UPPER_KEY + " " + upper);
upper = PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE;
}
}
}
}
}
return new OppositePropertyDetails(oppositeName, null, null, lower, upper);
} */
public static @Nullable OppositePropertyDetails createFromProperty(@NonNull Property property) {
IntegerValue oppositeLower = null;
Boolean oppositeOrdered = null;
Boolean oppositeUnique = null;
UnlimitedNaturalValue oppositeUpper = null;
IntegerValue lowerValue;
UnlimitedNaturalValue upperValue;
Type propertyType = property.getType();
Type type;
if (propertyType instanceof CollectionType) {
CollectionType collectionType = (CollectionType)propertyType;
type = collectionType.getElementType();
lowerValue = collectionType.getLowerValue();
upperValue = collectionType.getUpperValue();
if (collectionType.isOrdered() != PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_ORDERED) {
oppositeOrdered = collectionType.isOrdered();
}
if (collectionType.isUnique() != PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_UNIQUE) {
oppositeUnique = collectionType.isUnique();
}
}
else {
type = propertyType;
lowerValue = property.isIsRequired() ? ValueUtil.ONE_VALUE : ValueUtil.ZERO_VALUE;
upperValue = ValueUtil.UNLIMITED_ONE_VALUE;
}
if (!PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_LOWER_VALUE.equals(lowerValue)) {
oppositeLower = lowerValue;
}
if (!(property.getOpposite().isIsComposite() ? ValueUtil.UNLIMITED_ONE_VALUE : PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_UPPER_VALUE).equals(upperValue)) {
oppositeUpper = upperValue;
}
String name = property.getName();
//
// If there is an exact match for the no-EAnnotation DEFAULT values, then no EAnnotation is required.
//
if (name.equals(type.getName()) && (oppositeLower == null) && (oppositeOrdered == null) && (oppositeUnique == null) && (oppositeUpper == null)) {
return null;
}
//
// Otherwise the with-EAnnotation ANNOTATED values are the reference.
//
oppositeLower = null;
oppositeOrdered = null;
oppositeUnique = null;
oppositeUpper = null;
if (propertyType instanceof CollectionType) {
CollectionType collectionType = (CollectionType)propertyType;
if (collectionType.isOrdered() != PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_ORDERED) {
oppositeOrdered = collectionType.isOrdered();
}
if (collectionType.isUnique() != PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UNIQUE) {
oppositeUnique = collectionType.isUnique();
}
}
if (!PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE.equals(lowerValue)) {
oppositeLower = lowerValue;
}
if (!PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE.equals(upperValue)) {
oppositeUpper = upperValue;
}
return new OppositePropertyDetails(name, oppositeOrdered, oppositeUnique, oppositeLower, oppositeUpper);
}
public static @NonNull OppositePropertyDetails createImplicitFromEReference(@NonNull EReference eReference) {
assert eReference.getEOpposite() == null;
EClass eClass = ClassUtil.nonNullState(eReference.getEContainingClass());
String oppositeName = ClassUtil.nonNullState(eClass.getName());
IntegerValue oppositeLower = null;
Boolean oppositeOrdered = null;
Boolean oppositeUnique = null;
UnlimitedNaturalValue oppositeUpper = null;
if (eReference.isContainment()) {
oppositeOrdered = Boolean.FALSE;
oppositeUnique = Boolean.FALSE;
oppositeLower = ValueUtil.ZERO_VALUE;
oppositeUpper = ValueUtil.UNLIMITED_ONE_VALUE;
}
else {
oppositeOrdered = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_ORDERED;
oppositeUnique = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_UNIQUE;
oppositeLower = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_LOWER_VALUE;
oppositeUpper = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_UPPER_VALUE;
}
return new OppositePropertyDetails(oppositeName, oppositeOrdered, oppositeUnique, oppositeLower, oppositeUpper);
}
public static @NonNull OppositePropertyDetails createImplicitFromProperty(@NonNull Property asProperty) {
org.eclipse.ocl.pivot.Class asClass = PivotUtil.getOwningClass(asProperty);
String oppositeName = PivotUtil.getName(asClass);
IntegerValue oppositeLower = null;
Boolean oppositeOrdered = null;
Boolean oppositeUnique = null;
UnlimitedNaturalValue oppositeUpper = null;
if (asProperty.isIsComposite()) {
oppositeOrdered = Boolean.FALSE;
oppositeUnique = Boolean.FALSE;
oppositeLower = ValueUtil.ZERO_VALUE;
oppositeUpper = ValueUtil.UNLIMITED_ONE_VALUE;
}
else {
oppositeOrdered = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_ORDERED;
oppositeUnique = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_UNIQUE;
oppositeLower = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_LOWER_VALUE;
oppositeUpper = PivotConstantsInternal.DEFAULT_IMPLICIT_OPPOSITE_UPPER_VALUE;
}
return new OppositePropertyDetails(oppositeName, oppositeOrdered, oppositeUnique, oppositeLower, oppositeUpper);
}
protected final @Nullable String name;
protected final @Nullable Boolean ordered;
protected final @Nullable Boolean unique;
protected final @Nullable IntegerValue lower;
protected final @Nullable UnlimitedNaturalValue upper;
public OppositePropertyDetails(@Nullable String name, @Nullable Boolean ordered, @Nullable Boolean unique, @Nullable IntegerValue lower, @Nullable UnlimitedNaturalValue upper) {
this.name = name;
this.ordered = ordered;
this.unique = unique;
this.lower = lower;
this.upper = upper;
}
public void addToDetails(@NonNull EMap<String, String> eAnnotationDetails) {
String name2 = name;
if (name2 == null) {
eAnnotationDetails.removeKey(BODY_KEY);
}
else {
eAnnotationDetails.put(BODY_KEY, name2);
}
IntegerValue lower2 = lower;
if (lower2 == null) {
eAnnotationDetails.removeKey(LOWER_KEY);
}
else {
eAnnotationDetails.put(LOWER_KEY, lower2.toString());
}
Boolean ordered2 = ordered;
if (ordered2 == null) {
eAnnotationDetails.removeKey(ORDERED_KEY);
}
else {
eAnnotationDetails.put(ORDERED_KEY, ordered2.toString());
}
Boolean unique2 = unique;
if (unique2 == null) {
eAnnotationDetails.removeKey(UNIQUE_KEY);
}
else {
eAnnotationDetails.put(UNIQUE_KEY, unique2.toString());
}
UnlimitedNaturalValue upper2 = upper;
if (upper2 == null) {
eAnnotationDetails.removeKey(UPPER_KEY);
}
else if (upper2.isUnlimited()) {
eAnnotationDetails.put(UPPER_KEY, "-1");
}
else {
eAnnotationDetails.put(UPPER_KEY, upper2.toString());
}
}
public void addDetails(@NonNull Map<@NonNull String, @NonNull String> eAnnotationDetails) {
String name2 = name;
if (name2 == null) {
eAnnotationDetails.remove(BODY_KEY);
}
else {
eAnnotationDetails.put(BODY_KEY, name2);
}
IntegerValue lower2 = lower;
if (lower2 == null) {
eAnnotationDetails.remove(LOWER_KEY);
}
else {
eAnnotationDetails.put(LOWER_KEY, lower2.toString());
}
Boolean ordered2 = ordered;
if (ordered2 == null) {
eAnnotationDetails.remove(ORDERED_KEY);
}
else {
eAnnotationDetails.put(ORDERED_KEY, ordered2.toString());
}
Boolean unique2 = unique;
if (unique2 == null) {
eAnnotationDetails.remove(UNIQUE_KEY);
}
else {
eAnnotationDetails.put(UNIQUE_KEY, unique2.toString());
}
UnlimitedNaturalValue upper2 = upper;
if (upper2 == null) {
eAnnotationDetails.remove(UPPER_KEY);
}
else if (upper2.isUnlimited()) {
eAnnotationDetails.put(UPPER_KEY, "-1");
}
else {
eAnnotationDetails.put(UPPER_KEY, upper2.toString());
}
}
public @Nullable IntegerValue basicGetLower() {
return lower;
}
public @Nullable String basicGetName() {
return name;
}
public @Nullable UnlimitedNaturalValue basicGetUpper() {
return upper;
}
public @Nullable Boolean basicIsOrdered() {
return ordered;
}
public @Nullable Boolean basicIsUnique() {
return unique;
}
public @NonNull IntegerValue getLower() {
return ClassUtil.nonNullState(lower);
}
public @NonNull UnlimitedNaturalValue getUpper() {
return ClassUtil.nonNullState(upper);
}
public @NonNull String getName() {
return ClassUtil.nonNullState(name);
}
public @NonNull Boolean isOrdered() {
return ClassUtil.nonNullState(ordered);
}
public @NonNull Boolean isUnique() {
return ClassUtil.nonNullState(unique);
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append(name);
s.append("[");
s.append(lower);
s.append("..");
s.append(upper);
s.append("]{");
s.append(ordered ? "ordered" : "!ordered");
s.append(",");
s.append(unique ? "unique" : "!unique");
s.append("}");
return s.toString();
}
}