/*
* Copyright (c) 2014, 2015 CEA LIST 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 (CEA LIST) - initial API and implementation
*/
package org.eclipse.ocl.pivot.uml.internal.library;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.library.AbstractProperty;
import org.eclipse.ocl.pivot.utilities.MetamodelManager;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
import org.eclipse.ocl.pivot.values.InvalidValueException;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.InstanceValue;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralNull;
import org.eclipse.uml2.uml.LiteralReal;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.ValueSpecification;
/**
* An instance of InstanceSlotNavigationProperty supports evaluation of
* a property call that navigates a relationship to a UML InstanceSpecification slot.
*/
public class InstanceSlotNavigationProperty extends AbstractProperty
{
protected final org.eclipse.uml2.uml.@NonNull Property property;
protected final @Nullable CollectionTypeId collectionTypeId; // Non null for a Collection value
public InstanceSlotNavigationProperty(org.eclipse.uml2.uml.@NonNull Property property, @Nullable CollectionTypeId collectionTypeId) {
this.property = property;
this.collectionTypeId = collectionTypeId;
}
@Override
public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue) {
if (sourceValue != null) {
InstanceSpecification instanceSpecification = (InstanceSpecification)sourceValue;
for (Slot slot : instanceSpecification.getSlots()) {
if (slot.getDefiningFeature() == property) {
List<ValueSpecification> values = slot.getValues();
CollectionTypeId collectionTypeId2 = collectionTypeId;
int size = values.size();
if (collectionTypeId2 != null) {
List<Object> unboxedValues = new ArrayList<Object>(size);
for (ValueSpecification value : values) {
unboxedValues.add(valueOf(executor, value));
}
IdResolver idResolver = executor.getIdResolver();
return idResolver.createCollectionOfAll(collectionTypeId2, unboxedValues);
}
else if (size >= 1) {
ValueSpecification valueSpecification = values.get(0);
if (valueSpecification instanceof OpaqueExpression) {
try {
MetamodelManager metamodelManager = executor.getMetamodelManager();
ExpressionInOCL specification = metamodelManager.getASOf(ExpressionInOCL.class, valueSpecification);
if (specification == null) {
throw new InvalidValueException("Missing spec for " + specification);
}
ExpressionInOCL query = metamodelManager.parseSpecification(specification);
OCLExpression bodyExpression = query.getOwnedBody();
assert bodyExpression != null;
Object umlValue = executor.evaluate(bodyExpression);
return metamodelManager.getEnvironmentFactory().getIdResolver().boxedValueOf(umlValue);
} catch (ParserException e) {
throw new InvalidValueException(e, "Parse fail for " + valueSpecification);
}
}
else {
return valueOf(executor, valueSpecification);
}
}
else {
throw new InvalidValueException("no ValueSpecification in Slot");
}
}
}
}
return null;
}
private @Nullable Object valueOf(@NonNull Executor executor, @Nullable ValueSpecification valueSpecification) {
if (valueSpecification == null) {
throw new InvalidValueException("null ValueSpecification in Slot");
}
if (valueSpecification instanceof LiteralBoolean) {
return ((LiteralBoolean)valueSpecification).booleanValue();
}
if (valueSpecification instanceof LiteralInteger) {
return ValueUtil.integerValueOf(((LiteralInteger)valueSpecification).getValue());
}
if (valueSpecification instanceof LiteralNull) {
return null;
}
if (valueSpecification instanceof LiteralReal) {
return ValueUtil.realValueOf(((LiteralReal)valueSpecification).getValue());
}
if (valueSpecification instanceof LiteralString) {
return ((LiteralString)valueSpecification).getValue();
}
if (valueSpecification instanceof LiteralUnlimitedNatural) {
int unlimitedValue = ((LiteralUnlimitedNatural)valueSpecification).unlimitedValue();
return unlimitedValue < 0 ? ValueUtil.UNLIMITED_VALUE : ValueUtil.integerValueOf(unlimitedValue);
}
if (valueSpecification instanceof InstanceValue) {
InstanceSpecification ecoreInstance = ((InstanceValue)valueSpecification).getInstance();
return ecoreInstance != null ? executor.getIdResolver().boxedValueOf(ecoreInstance) : null;
}
throw new UnsupportedOperationException(getClass().getSimpleName() + ".valueOf " + valueSpecification.eClass().getName());
}
}