PropertyImpl.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.aadl2.impl;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;
import org.osate.aadl2.Aadl2Package;
import org.osate.aadl2.AbstractNamedValue;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.Feature;
import org.osate.aadl2.FeatureGroup;
import org.osate.aadl2.MetaclassReference;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.PortConnection;
import org.osate.aadl2.Property;
import org.osate.aadl2.PropertyAssociation;
import org.osate.aadl2.PropertyExpression;
import org.osate.aadl2.PropertyOwner;
import org.osate.aadl2.Subcomponent;
import org.osate.aadl2.instance.InstanceObject;
import org.osate.aadl2.instance.util.InstanceUtil.InstantiatedClassifier;
import org.osate.aadl2.properties.EvaluatedProperty;
import org.osate.aadl2.properties.EvaluationContext;
import org.osate.aadl2.properties.InvalidModelException;
import org.osate.aadl2.properties.PropertyAcc;
import org.osate.aadl2.properties.PropertyDoesNotApplyToHolderException;
import org.osate.aadl2.properties.PropertyEvaluationResult;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Property</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* </p>
* <ul>
* <li>{@link org.osate.aadl2.impl.PropertyImpl#isInherit <em>Inherit</em>}</li>
* <li>{@link org.osate.aadl2.impl.PropertyImpl#getDefaultValue <em>Default Value</em>}</li>
* <li>{@link org.osate.aadl2.impl.PropertyImpl#getAppliesToMetaclasses <em>Applies To Metaclass</em>}</li>
* <li>{@link org.osate.aadl2.impl.PropertyImpl#getAppliesToClassifiers <em>Applies To Classifier</em>}</li>
* <li>{@link org.osate.aadl2.impl.PropertyImpl#getAppliesTos <em>Applies To</em>}</li>
* <li>{@link org.osate.aadl2.impl.PropertyImpl#isEmptyListDefault <em>Empty List Default</em>}</li>
* </ul>
*
* @generated
*/
public class PropertyImpl extends BasicPropertyImpl implements Property {
/**
* The default value of the '{@link #isInherit() <em>Inherit</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isInherit()
* @generated
* @ordered
*/
protected static final boolean INHERIT_EDEFAULT = false;
/**
* The cached value of the '{@link #isInherit() <em>Inherit</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isInherit()
* @generated
* @ordered
*/
protected boolean inherit = INHERIT_EDEFAULT;
/**
* The cached value of the '{@link #getDefaultValue() <em>Default Value</em>}' containment reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getDefaultValue()
* @generated
* @ordered
*/
protected PropertyExpression defaultValue;
/**
* The cached value of the '{@link #getAppliesTos() <em>Applies To</em>}' containment reference list.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getAppliesTos()
* @generated
* @ordered
*/
protected EList<PropertyOwner> appliesTos;
/**
* The default value of the '{@link #isEmptyListDefault() <em>Empty List Default</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isEmptyListDefault()
* @generated
* @ordered
*/
protected static final boolean EMPTY_LIST_DEFAULT_EDEFAULT = false;
/**
* The cached value of the '{@link #isEmptyListDefault() <em>Empty List Default</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isEmptyListDefault()
* @generated
* @ordered
*/
protected boolean emptyListDefault = EMPTY_LIST_DEFAULT_EDEFAULT;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected PropertyImpl() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return Aadl2Package.eINSTANCE.getProperty();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean isInherit() {
return inherit;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setInherit(boolean newInherit) {
boolean oldInherit = inherit;
inherit = newInherit;
if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET, Aadl2Package.PROPERTY__INHERIT, oldInherit, inherit));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public PropertyExpression getDefaultValue() {
return defaultValue;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public NotificationChain basicSetDefaultValue(PropertyExpression newDefaultValue, NotificationChain msgs) {
PropertyExpression oldDefaultValue = defaultValue;
defaultValue = newDefaultValue;
if (eNotificationRequired()) {
ENotificationImpl notification = new ENotificationImpl(this, Notification.SET,
Aadl2Package.PROPERTY__DEFAULT_VALUE, oldDefaultValue, newDefaultValue);
if (msgs == null) {
msgs = notification;
} else {
msgs.add(notification);
}
}
return msgs;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setDefaultValue(PropertyExpression newDefaultValue) {
if (newDefaultValue != defaultValue) {
NotificationChain msgs = null;
if (defaultValue != null) {
msgs = ((InternalEObject) defaultValue).eInverseRemove(this,
EOPPOSITE_FEATURE_BASE - Aadl2Package.PROPERTY__DEFAULT_VALUE, null, msgs);
}
if (newDefaultValue != null) {
msgs = ((InternalEObject) newDefaultValue).eInverseAdd(this,
EOPPOSITE_FEATURE_BASE - Aadl2Package.PROPERTY__DEFAULT_VALUE, null, msgs);
}
msgs = basicSetDefaultValue(newDefaultValue, msgs);
if (msgs != null) {
msgs.dispatch();
}
} else if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET, Aadl2Package.PROPERTY__DEFAULT_VALUE, newDefaultValue,
newDefaultValue));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public EList<PropertyOwner> getAppliesTos() {
if (appliesTos == null) {
appliesTos = new EObjectContainmentEList<>(PropertyOwner.class, this,
Aadl2Package.PROPERTY__APPLIES_TO);
}
return appliesTos;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public PropertyOwner createAppliesTo(EClass eClass) {
PropertyOwner newAppliesTo = (PropertyOwner) create(eClass);
getAppliesTos().add(newAppliesTo);
return newAppliesTo;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean isEmptyListDefault() {
return emptyListDefault;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void setEmptyListDefault(boolean newEmptyListDefault) {
boolean oldEmptyListDefault = emptyListDefault;
emptyListDefault = newEmptyListDefault;
if (eNotificationRequired()) {
eNotify(new ENotificationImpl(this, Notification.SET, Aadl2Package.PROPERTY__EMPTY_LIST_DEFAULT,
oldEmptyListDefault, emptyListDefault));
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public PropertyExpression createDefaultValue(EClass eClass) {
PropertyExpression newDefaultValue = (PropertyExpression) create(eClass);
setDefaultValue(newDefaultValue);
return newDefaultValue;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<MetaclassReference> getAppliesToMetaclasses() {
// DONE: implement this method to return the 'Applies To Metaclass'
// reference list
EList<MetaclassReference> result = new BasicEList<>();
for (PropertyOwner po : getAppliesTos()) {
if (po instanceof MetaclassReference) {
result.add((MetaclassReference) po);
}
}
return result;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<Classifier> getAppliesToClassifiers() {
// DONE: implement this method to return the 'Applies To Classifier'
// reference list
EList<Classifier> result = new BasicEList<>();
for (PropertyOwner po : getAppliesTos()) {
if (po instanceof Classifier) {
result.add((Classifier) po);
}
}
return result;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID) {
case Aadl2Package.PROPERTY__DEFAULT_VALUE:
return basicSetDefaultValue(null, msgs);
case Aadl2Package.PROPERTY__APPLIES_TO:
return ((InternalEList<?>) getAppliesTos()).basicRemove(otherEnd, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case Aadl2Package.PROPERTY__INHERIT:
return isInherit();
case Aadl2Package.PROPERTY__DEFAULT_VALUE:
return getDefaultValue();
case Aadl2Package.PROPERTY__APPLIES_TO_METACLASS:
return getAppliesToMetaclasses();
case Aadl2Package.PROPERTY__APPLIES_TO_CLASSIFIER:
return getAppliesToClassifiers();
case Aadl2Package.PROPERTY__APPLIES_TO:
return getAppliesTos();
case Aadl2Package.PROPERTY__EMPTY_LIST_DEFAULT:
return isEmptyListDefault();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@SuppressWarnings("unchecked")
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case Aadl2Package.PROPERTY__INHERIT:
setInherit((Boolean) newValue);
return;
case Aadl2Package.PROPERTY__DEFAULT_VALUE:
setDefaultValue((PropertyExpression) newValue);
return;
case Aadl2Package.PROPERTY__APPLIES_TO_METACLASS:
getAppliesToMetaclasses().clear();
getAppliesToMetaclasses().addAll((Collection<? extends MetaclassReference>) newValue);
return;
case Aadl2Package.PROPERTY__APPLIES_TO_CLASSIFIER:
getAppliesToClassifiers().clear();
getAppliesToClassifiers().addAll((Collection<? extends Classifier>) newValue);
return;
case Aadl2Package.PROPERTY__APPLIES_TO:
getAppliesTos().clear();
getAppliesTos().addAll((Collection<? extends PropertyOwner>) newValue);
return;
case Aadl2Package.PROPERTY__EMPTY_LIST_DEFAULT:
setEmptyListDefault((Boolean) newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case Aadl2Package.PROPERTY__INHERIT:
setInherit(INHERIT_EDEFAULT);
return;
case Aadl2Package.PROPERTY__DEFAULT_VALUE:
setDefaultValue((PropertyExpression) null);
return;
case Aadl2Package.PROPERTY__APPLIES_TO_METACLASS:
getAppliesToMetaclasses().clear();
return;
case Aadl2Package.PROPERTY__APPLIES_TO_CLASSIFIER:
getAppliesToClassifiers().clear();
return;
case Aadl2Package.PROPERTY__APPLIES_TO:
getAppliesTos().clear();
return;
case Aadl2Package.PROPERTY__EMPTY_LIST_DEFAULT:
setEmptyListDefault(EMPTY_LIST_DEFAULT_EDEFAULT);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case Aadl2Package.PROPERTY__INHERIT:
return inherit != INHERIT_EDEFAULT;
case Aadl2Package.PROPERTY__DEFAULT_VALUE:
return defaultValue != null;
case Aadl2Package.PROPERTY__APPLIES_TO_METACLASS:
return !getAppliesToMetaclasses().isEmpty();
case Aadl2Package.PROPERTY__APPLIES_TO_CLASSIFIER:
return !getAppliesToClassifiers().isEmpty();
case Aadl2Package.PROPERTY__APPLIES_TO:
return appliesTos != null && !appliesTos.isEmpty();
case Aadl2Package.PROPERTY__EMPTY_LIST_DEFAULT:
return emptyListDefault != EMPTY_LIST_DEFAULT_EDEFAULT;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public String toString() {
if (eIsProxy()) {
return super.toString();
}
StringBuilder result = new StringBuilder(super.toString());
result.append(" (inherit: ");
result.append(inherit);
result.append(", emptyListDefault: ");
result.append(emptyListDefault);
result.append(')');
return result.toString();
}
public PropertyEvaluationResult evaluate(EvaluationContext ctx, int depth) {
List<PropertyAssociation> pas = getPropertyValue(ctx).getAssociations();
List<EvaluatedProperty> vals = new LinkedList<>();
for (PropertyAssociation pa : pas) {
vals.add(pa.evaluate(ctx, depth));
if (!pa.isAppend()) {
break;
}
}
/*
* NB. Do not fix Issue 2387 here! Doing so caused a different problem. Namely,
* if a property with a default value is explicit associated with a value in one place
* in the model, it's going to force model instantiation to create explicit property
* associations in the instance model that bind the default value to the property AT
* ALL OTHER PLACES THE PROPERTY IS APPLICABLE. This is undesirable.
*/
return new PropertyEvaluationResult(pas.isEmpty() ? null : pas.get(0), vals);
}
private PropertyAcc getPropertyValue(EvaluationContext ctx) throws IllegalStateException, InvalidModelException,
PropertyDoesNotApplyToHolderException, IllegalArgumentException {
// Error if the property is not acceptable
final PropertyAcc pas = new PropertyAcc(this);
getPropertyValueInternal(ctx, pas);
return pas;
}
public final void getPropertyValueInternal(EvaluationContext ctx, final PropertyAcc paa)
throws InvalidModelException {
InstanceObject io = ctx.getInstanceObject();
// OsateDebug.osateDebug("here1 " + io + paa);
/*
* Only relevant for connection instances
*/
if (ctx.getSCProp() != null) {
if (paa.add(ctx.getSCProp())) {
return;
}
}
/*
* First see if the property is defined locally in the instance. Such
* local property associations arise from component property
* associations in the declarative spec, from explicit programmatic
* setting of the property, or as cached results from earlier property
* lookups.
*/
if (paa.addLocal(io)) {
return;
}
getPropertyValueFromDeclarativeModel(ctx, paa);
/*
* If the property is "inherit", get it from the enclosing component
* instance. Don't short-circuit this step because the property caching
* during instantiation doesn't catch contained property values that may
* be attached to an ancestor instance and that might be inherited by
* this instance.
*/
if (isInherit()) {
io = (InstanceObject) io.eContainer();
if (io != null) {
getPropertyValueInternal(new EvaluationContext(io, ctx.getClassifierCache()), paa);
}
}
}
protected void getPropertyValueFromDeclarativeModel(EvaluationContext ctx, PropertyAcc pas)
throws InvalidModelException {
InstanceObject io = ctx.getInstanceObject();
List<? extends NamedElement> compDecls = io.getInstantiatedObjects();
// FIXME: compDecls == null for connection instances
// OsateDebug.osateDebug("[PropertyImpl] getPropertyValueFromDeclarativeModel" + compDecls);
if (compDecls == null) {
}
// Here we assume compDecls is empty or has only one element
if (!compDecls.isEmpty()) {
NamedElement compDecl = compDecls.get(0);
if (compDecl == null) {
return;
}
InstantiatedClassifier ic = ctx.getClassifierCache().get(io);
Classifier cl = (ic == null) ? null : ic.getClassifier();
// OsateDebug.osateDebug("compDecls" + compDecl);
if (compDecl instanceof Subcomponent) {
((SubcomponentImpl) compDecl).getPropertyValue(this, pas, cl, false);
} else if (compDecl instanceof FeatureGroup) {
((FeatureGroupImpl) compDecl).getPropertyValue(this, pas, cl, false);
} else if (compDecl instanceof Feature) {
((FeatureImpl) compDecl).getPropertyValue(this, pas, cl, false);
} else if (compDecl instanceof PortConnection) {
((PortConnectionImpl) compDecl).getPropertyValue(this, pas);
} else {
compDecl.getPropertyValueInternal(this, pas, true);
}
}
}
public EvaluatedProperty evaluateDefault(EvaluationContext ctx) {
return null;
}
public boolean equals(Object p) {
if (p instanceof Property) {
String p1Name = getQualifiedName();
String p2Name = ((Property) p).getQualifiedName();
if (p1Name != null) {
return p1Name.equalsIgnoreCase(p2Name);
}
}
return this == p;
}
public int hashCode() {
if (eIsProxy()) {
return eProxyURI().toString().hashCode();
}
return getQualifiedName() != null ? getQualifiedName().hashCode() : super.hashCode();
}
/*
* (non-Javadoc)
*
* @see org.osate.aadl2.AbstractNamedValue#sameAs(org.osate.aadl2.AbstractNamedValue)
*/
public boolean sameAs(AbstractNamedValue namedValue) {
return this == namedValue;
}
} // PropertyImpl