EMV2Properties.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.xtext.aadl2.errormodel.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.osate.aadl2.AbstractNamedValue;
import org.osate.aadl2.BasicPropertyAssociation;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.ComponentClassifier;
import org.osate.aadl2.ContainmentPathElement;
import org.osate.aadl2.Element;
import org.osate.aadl2.EnumerationLiteral;
import org.osate.aadl2.IntegerLiteral;
import org.osate.aadl2.ListValue;
import org.osate.aadl2.ModalPropertyValue;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.NamedValue;
import org.osate.aadl2.Property;
import org.osate.aadl2.PropertyAssociation;
import org.osate.aadl2.PropertyConstant;
import org.osate.aadl2.PropertyExpression;
import org.osate.aadl2.RealLiteral;
import org.osate.aadl2.RecordValue;
import org.osate.aadl2.StringLiteral;
import org.osate.aadl2.Subcomponent;
import org.osate.aadl2.instance.ComponentInstance;
import org.osate.aadl2.instance.SystemOperationMode;
import org.osate.xtext.aadl2.errormodel.errorModel.EMV2Path;
import org.osate.xtext.aadl2.errormodel.errorModel.EMV2PathElement;
import org.osate.xtext.aadl2.errormodel.errorModel.EMV2PropertyAssociation;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorBehaviorState;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorBehaviorStateMachine;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorEvent;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelLibrary;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelSubclause;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorPropagation;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorSource;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorTypes;
import org.osate.xtext.aadl2.errormodel.errorModel.TypeSet;
import org.osate.xtext.aadl2.errormodel.errorModel.TypeToken;
import org.osate.xtext.aadl2.properties.util.GetProperties;
public class EMV2Properties {
public static final String INVALID_OCCURRENCE_TYPE = "unknown_distribution";
/**
* convert enumeration literals or integer values possibly assigned as property constant into String labels
* @param val PropertyExpression
* @returns String
*/
public static String getEnumerationOrIntegerPropertyConstantPropertyValue(PropertyExpression val) {
// added code to handle integer value and use of property constant instead of enumeration literal
if (val instanceof NamedValue) {
AbstractNamedValue eval = ((NamedValue) val).getNamedValue();
if (eval instanceof EnumerationLiteral) {
return ((EnumerationLiteral) eval).getName();
} else if (eval instanceof PropertyConstant) {
return ((PropertyConstant) eval).getName();
}
} else if (val instanceof IntegerLiteral) {
return "" + ((IntegerLiteral) val).getValue();
} else if (val instanceof RealLiteral) {
return "" + ((RealLiteral) val).getValue();
}
return "";
}
public static PropertyExpression getPropertyValue(EMV2PropertyAssociation pa) {
if (pa != null) {
for (ModalPropertyValue modalPropertyValue : pa.getOwnedValues()) {
PropertyExpression val = resolvePropertyConstant(modalPropertyValue.getOwnedValue());
return val;
}
}
return null;
}
public static PropertyExpression getPropertyValue(BasicPropertyAssociation bpa) {
PropertyExpression pe = bpa.getValue();
return resolvePropertyConstant(pe);
}
private static PropertyExpression resolvePropertyConstant(PropertyExpression pe) {
if (pe instanceof NamedValue) {
NamedValue nv = (NamedValue) pe;
if (nv.getNamedValue() instanceof PropertyConstant) {
PropertyConstant pc = (PropertyConstant) nv.getNamedValue();
return pc.getConstantValue();
}
}
return pe;
}
/**
* retrieve the probability
* @param ci component instance, subcomponent, or classifier
* @param ne named element for which we retrieve the probability
* @param ts type set
* @return
*/
public static double getProbability(NamedElement ci, NamedElement ne, ErrorTypes ts) {
List<EMV2PropertyAssociation> PA = EMV2Properties.getOccurrenceDistributionProperty(ci, ne, ts);
double prob = 0;
for (EMV2PropertyAssociation emv2PropertyAssociation : PA) {
prob += EMV2Properties.getOccurrenceValue(emv2PropertyAssociation);
}
return prob;
}
public static double getProbability(NamedElement ci, NamedElement ne, TypeToken tt) {
double prob = 0;
if (tt == null) {
List<EMV2PropertyAssociation> PA = EMV2Properties.getOccurrenceDistributionProperty(ci, ne, null);
for (EMV2PropertyAssociation emv2PropertyAssociation : PA) {
prob += EMV2Properties.getOccurrenceValue(emv2PropertyAssociation);
}
} else {
for (ErrorTypes et : tt.getType()) {
prob += EMV2Properties.getProbability(ci, ne, et);
}
}
return prob;
}
/**
*
* @param element - the EMV2 element that refers to the artifact
* @param relatedComponent - the component (instance, subcomponent or classifier that have the property association
* @return - the text related to the description part of the hazards property. Null if not defined
*/
public static String getHazardDescription(NamedElement element, NamedElement relatedComponent) {
TypeSet ts = null;
if (element instanceof ErrorBehaviorState) {
ts = ((ErrorBehaviorState) element).getTypeSet();
}
if (element instanceof ErrorPropagation) {
ts = ((ErrorPropagation) element).getTypeSet();
}
if (element instanceof ErrorEvent) {
ts = ((ErrorEvent) element).getTypeSet();
}
if (element instanceof ErrorSource) {
ts = ((ErrorSource) element).getTypeTokenConstraint();
}
return getHazardDescription(element, relatedComponent, ts);
}
public static String getHazardDescription(NamedElement element, NamedElement relatedComponent, ErrorTypes ts) {
List<EMV2PropertyAssociation> PA = EMV2Properties.getHazardsProperty(relatedComponent, element, ts);
if (PA.isEmpty()) {
return null;
}
// XXX TODO we may get more than one back, one each for different types
PropertyExpression val = getPropertyValue(PA.get(0));
if (val instanceof RecordValue) {
RecordValue rv = (RecordValue) val;
EList<BasicPropertyAssociation> fields = rv.getOwnedFieldValues();
BasicPropertyAssociation xref = GetProperties.getRecordField(fields, "description");
if (xref != null) {
PropertyExpression peVal = getPropertyValue(xref);
if (peVal instanceof StringLiteral) {
return ((StringLiteral) peVal).getValue();
}
}
}
if (val instanceof ListValue) {
ListValue lv = (ListValue) val;
for (PropertyExpression pe : lv.getOwnedListElements()) {
if (pe instanceof RecordValue) {
RecordValue rv = (RecordValue) pe;
EList<BasicPropertyAssociation> fields = rv.getOwnedFieldValues();
BasicPropertyAssociation xref = GetProperties.getRecordField(fields, "description");
if (xref != null) {
PropertyExpression peVal = getPropertyValue(xref);
if (peVal instanceof StringLiteral) {
return ((StringLiteral) peVal).getValue();
}
}
}
}
}
return null;
}
/**
*
* @param element - the EMV2 element that referes to the artifact
* @param relatedComponent - the component the component (instance, subcomponent or classifier) that have the property association
* @return - the text related to the failure part of the hazards property. Null if not defined
*/
public static String getFailure(NamedElement element, NamedElement relatedComponent) {
TypeSet ts = null;
if (element instanceof ErrorBehaviorState) {
ts = ((ErrorBehaviorState) element).getTypeSet();
}
if (element instanceof ErrorPropagation) {
ts = ((ErrorPropagation) element).getTypeSet();
}
if (element instanceof ErrorEvent) {
ts = ((ErrorEvent) element).getTypeSet();
}
List<EMV2PropertyAssociation> PA = EMV2Properties.getHazardsProperty(relatedComponent, element, ts);
if (PA.isEmpty()) {
return null;
}
// XXX TODO we may get more than one back, one each for different types
PropertyExpression val = getPropertyValue(PA.get(0));
if (val instanceof RecordValue) {
RecordValue rv = (RecordValue) val;
EList<BasicPropertyAssociation> fields = rv.getOwnedFieldValues();
BasicPropertyAssociation xref = GetProperties.getRecordField(fields, "failure");
if (xref != null) {
PropertyExpression peVal = getPropertyValue(xref);
if (peVal instanceof StringLiteral) {
return ((StringLiteral) peVal).getValue();
}
}
}
if (val instanceof ListValue) {
ListValue lv = (ListValue) val;
for (PropertyExpression pe : lv.getOwnedListElements()) {
if (pe instanceof RecordValue) {
RecordValue rv = (RecordValue) pe;
EList<BasicPropertyAssociation> fields = rv.getOwnedFieldValues();
BasicPropertyAssociation xref = GetProperties.getRecordField(fields, "failure");
if (xref != null) {
PropertyExpression peVal = getPropertyValue(xref);
if (peVal instanceof StringLiteral) {
return ((StringLiteral) peVal).getValue();
}
}
}
}
}
return null;
}
/**
* retrieve the hazards property
* @param ci Component instance, subcomponent or classifier
* @param target target error model element
* @param ts TypeSet
* @return
*/
public static List<EMV2PropertyAssociation> getHazardsProperty(NamedElement ci, NamedElement target, TypeSet ts) {
List<EMV2PropertyAssociation> result = getProperty("EMV2::hazards", ci, target, ts);
if (result.isEmpty()) {
result = getProperty("ARP4761::hazards", ci, target, ts);
}
if (result.isEmpty()) {
result = getProperty("MILSTD882::hazards", ci, target, ts);
}
return result;
}
public static List<EMV2PropertyAssociation> getARP4761HazardsProperty(NamedElement ci, NamedElement target,
TypeSet ts) {
List<EMV2PropertyAssociation> result = getProperty("ARP4761::hazards", ci, target, ts);
return result;
}
public static List<EMV2PropertyAssociation> getMILSTD882HazardsProperty(NamedElement ci, NamedElement target,
TypeSet ts) {
List<EMV2PropertyAssociation> result = getProperty("MILSTD882::hazards", ci, target, ts);
return result;
}
public static List<EMV2PropertyAssociation> getHazardsProperty(NamedElement ci, NamedElement target,
ErrorTypes ts) {
List<EMV2PropertyAssociation> result = getProperty("EMV2::hazards", ci, target, ts);
if (result.isEmpty()) {
result = getProperty("ARP4761::hazards", ci, target, ts);
}
if (result.isEmpty()) {
result = getProperty("MILSTD882::hazards", ci, target, ts);
}
return result;
}
/**
* Retrieve the value of the OccurenceDistribution property of the
* EMV2 property. You can use it like this:
* ContainedNamedElement PA = EM2Util.getOccurenceDistributionProperty(instance,null,ee,null);
* res = EM2Util.getOccurenceValue (PA);
*
* @see Util
* @param ci Component instance, subcomponent or classifier that contains the property
* @param target the property
* @param ts corresponding typeset or null
* @return
*/
public static List<EMV2PropertyAssociation> getOccurrenceDistributionProperty(NamedElement ci, NamedElement target,
ErrorTypes ts) {
List<EMV2PropertyAssociation> result = getProperty("EMV2::OccurrenceDistribution", ci, target, ts);
return result;
}
/**
* Retrieve the value associated with a containment path
* See RDB action to see how it is used.
*
* @param PA value get from getOccurenceDistributionProperty
*/
public static double getOccurrenceValue(final EMV2PropertyAssociation PA) {
double result;
result = 0;
if (PA == null) {
return 0;
}
PropertyExpression val = getPropertyValue(PA);
if (val instanceof RecordValue) {
RecordValue rv = (RecordValue) val;
EList<BasicPropertyAssociation> fields = rv.getOwnedFieldValues();
// for all error types/aliases in type set or the element identified in the containment clause
for (BasicPropertyAssociation bpa : fields) {
if (bpa.getProperty().getName().equalsIgnoreCase("probabilityvalue")) {
PropertyExpression bva = getPropertyValue(bpa);
if (bva instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) bva;
result = rl.getScaledValue();
}
}
}
}
return result;
}
/**
*
*/
public static double getRealValue(final EMV2PropertyAssociation PA) {
if (PA == null) {
return 0.0;
}
PropertyExpression val = getPropertyValue(PA);
if (val instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) val;
return rl.getValue();
}
return 0.0;
}
public static double getModalRealValue(EMV2PropertyAssociation pa, SystemOperationMode som) {
if (!isModal(pa)) {
PropertyExpression val = getPropertyValue(pa);
if (val instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) val;
return rl.getValue();
}
} else if (som != null) {
PropertyExpression defaultPE = null;
// find value in SOM
for (ModalPropertyValue mpv : pa.getOwnedValues()) {
if (mpv.getInModes() == null || mpv.getInModes().size() == 0) {
defaultPE = resolvePropertyConstant(mpv.getOwnedValue());
} else if (mpv.getInModes().contains(som)) {
PropertyExpression val = resolvePropertyConstant(mpv.getOwnedValue());
if (val instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) val;
return rl.getValue();
}
}
}
// default
if (defaultPE != null) {
if (defaultPE instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) defaultPE;
return rl.getValue();
}
}
// use global default
PropertyExpression val = resolvePropertyConstant(pa.getProperty().getDefaultValue());
if (val instanceof RealLiteral) {
RealLiteral rl = (RealLiteral) val;
return rl.getValue();
}
}
return 0.0;
}
public static boolean isModal(EMV2PropertyAssociation pa) {
int count = pa.getOwnedValues().size();
if (count > 1) {
return true;
}
if (count == 0) {
return false;
}
return pa.getOwnedValues().get(0).getInModes() != null && !pa.getOwnedValues().get(0).getInModes().isEmpty();
}
/**
* get list of property associations in enclosing object within the error annex that has a properties section.
* ErrorModelLibrary, ErrorBehaviorStateMachine have properties sections
* Note: we assume the PA list in the subclause has been handled.
* @param element declarative model element or error annex element
* @return PS list of ErrorModelLibrary, ErrorBehaviorStateMachine
*/
public static List<EMV2PropertyAssociation> getPropertyAssociationListInContext(Element element) {
EObject container = element;
while (container != null) {
if (container instanceof ErrorModelSubclause) {
return ((ErrorModelSubclause) container).getProperties();
}
if (container instanceof ErrorModelLibrary) {
return ((ErrorModelLibrary) container).getProperties();
}
if (container instanceof ErrorBehaviorStateMachine) {
return ((ErrorBehaviorStateMachine) container).getProperties();
}
container = container.eContainer();
}
return Collections.emptyList();
}
/** return list of property associations that meet the property name
*
* @param props property association list from the properties section
* @param propertyName name of property
* @return EList<PropertyAssociation>
*/
public static List<PropertyAssociation> getPropertyAssociationsMatchingName(List<PropertyAssociation> props,
String propertyName) {
List<PropertyAssociation> result = new ArrayList<PropertyAssociation>();
for (PropertyAssociation propertyAssociation : props) {
Property prop = propertyAssociation.getProperty();
String name = prop.getQualifiedName();
if (propertyName.equalsIgnoreCase(name)) {
result.add(propertyAssociation);
}
}
return result;
}
/**
* return containment path of all PA in list that match the target.
* Should be only one matching.
* @param props list of property associations from the properties section in the error model of ci
* @param propertyName name of property we are looking for
* @param target the error model element
* @param ciStack stack of nested CI below the ci of the props; those names may show up in the path
* @return list of paths
*/
public static List<EMV2PropertyAssociation> getMatchingPropertiesInList(List<EMV2PropertyAssociation> props,
String propertyName, NamedElement target, Stack<NamedElement> ciStack, ErrorTypes ts) {
if (props.isEmpty()) {
return Collections.emptyList();
}
List<EMV2PropertyAssociation> result = new ArrayList<EMV2PropertyAssociation>();
for (EMV2PropertyAssociation propertyAssociation : props) {
Property prop = propertyAssociation.getProperty();
String name = prop.getQualifiedName();
if (propertyName.equalsIgnoreCase(name)) {
EMV2PropertyAssociation res = isErrorModelElementProperty(propertyAssociation, target, ciStack, ts);
if (res != null) {
result.add(res);
}
}
}
return result;
}
/**
* return containment paths of all PA in list whose property name and target/ts match
* @param props
* @param propertyName
* @param target
* @param ts
* @return list of PropertyAssociation
*/
public static List<EMV2PropertyAssociation> getMatchingPropertiesInList(List<EMV2PropertyAssociation> props,
String propertyName, NamedElement target, ErrorTypes ts) {
return getMatchingPropertiesInList(props, propertyName, target, null, ts);
}
/**
* check to see if the first part of the path matches the stack.
* Note, the order of items on the stack is the inverse of that in the path.
* If ciStack is null or empty return true.
* @param ciStack
* @param cpes
* @return
*/
private static boolean matchCIStack(Stack<NamedElement> ciStack, ContainmentPathElement cp) {
if (cp == null && (ciStack == null || ciStack.isEmpty())) {
return true;
}
if (cp == null && (ciStack != null && !ciStack.isEmpty())
|| cp != null && (ciStack == null || ciStack.isEmpty())) {
return false;
}
ContainmentPathElement emv2ce = cp;
for (int idx = ciStack.size() - 1; idx >= 0; idx--) {
NamedElement namedElement = ciStack.get(idx);
if (emv2ce == null || !namedElement.getName().equalsIgnoreCase(emv2ce.getNamedElement().getName())) {
return false;
} else {
emv2ce = emv2ce.getPath();
}
}
return true;
}
private static boolean matchCIStack(Stack<NamedElement> ciStack, EMV2PathElement cp) {
if (cp == null || (ciStack == null || ciStack.isEmpty())) {
return true;
}
EMV2PathElement emv2ce = cp;
for (int idx = ciStack.size() - 1; idx >= 0; idx--) {
NamedElement namedElement = ciStack.get(idx);
if (emv2ce == null || !namedElement.getName().equalsIgnoreCase(emv2ce.getNamedElement().getName())) {
return false;
} else {
emv2ce = emv2ce.getPath();
}
}
return true;
}
/**
* return the containment path if the stack combined with the target and optionally the type set match the containment path of a property association.
* It is sufficient for one of the paths in the PA to match.
* ciStack represents the path from the context of the PA to the component instance whose property we want to retrieve
* The desired type set ts must be contained in the type set named in the containment path
* @param propertyAssociation PropertyAssociation that is the candidate
* @param ciStack (can be null or empty) ComponentInstance in instance model hierarchy with the error model element, whose property we are retrieving (or null)
* @param target Element the target object in the error model whose property we retrieve
* @param ts type set that must contain the last element if it is a type
* @return ContainedNamedElement the containment path that matches
*/
public static EMV2PropertyAssociation isErrorModelElementProperty(EMV2PropertyAssociation propertyAssociation,
NamedElement target, Stack<NamedElement> ciStack, ErrorTypes ts) {
boolean matchStack = false;
EList<EMV2Path> applies = propertyAssociation.getEmv2Path();
for (EMV2Path emv2Path : applies) {
ContainmentPathElement cp = emv2Path.getContainmentPath();
if (cp != null) {
matchStack = matchCIStack(ciStack, cp);
} else {
matchStack = matchCIStack(ciStack, emv2Path.getEmv2Target());
}
if (matchStack) {
// we are past the component portion of the path
String targetName = EMV2Util.getPrintName(target);
NamedElement pathTargetEME = EMV2Util.getErrorModelElement(emv2Path);
String pathName = EMV2Util.getPrintName(pathTargetEME);
if (targetName.equalsIgnoreCase(pathName)) {
ErrorTypes typeelement = EMV2Util.getErrorType(emv2Path);
if (typeelement != null && ts != null) {
// check to see if the desired ts is contained in the PA containment path
if (EMV2TypeSetUtil.contains(ts, typeelement) || EMV2TypeSetUtil.contains(typeelement, ts)) {
return propertyAssociation;
}
} else {
return propertyAssociation;
}
}
}
}
return null;
}
/**
* find property by first looking for it down the component instance hierarchy to ci
* Then try to find it in the local context if not null. The context is the context object of the referenced target.
* For example: the transition for a state reference.
* Finally, we look for the property at the definition site of the referenced object.
* NOTE: the target element may actually be contained in a different context from the context in which we are interested in its property.
* For example, we are interested in the occurrence distribution for an error state. It actually is contained in an error behavior state machine.
* We are interested in its property value in the context of of the reference to the state, e.g., an error source.
* In some cases we are interested in the state as it is associated with the component via the use behavior clause.
* In that case there is no local context for the state reference.
* @param propertyName String
* @param ci ComponentInstance the component instance, subcomponent, or classifier with the error model element, whose property we are retrieving
* @param target Element the target object in the error model whose property we retrieve (the element may carry an error type)
* @param ts Type Set null or any error type in the type set as part of the target error model element
* @return
*/
public static List<EMV2PropertyAssociation> getProperty(String propertyName, NamedElement ci, NamedElement target,
ErrorTypes ts) {
List<EMV2PropertyAssociation> result = getPropertyInInstanceHierarchy(propertyName, ci, target, ts);
if (result.isEmpty()) {
// look up in context of target definition
// for example: for a state reference the properties section of the EBSM that defines the state
List<EMV2PropertyAssociation> props = getPropertyAssociationListInContext(target);
if (!props.isEmpty()) {
result = getMatchingPropertiesInList(props, propertyName, target, ts);
}
}
return result;
}
/**
* recurse up the component hierarchy to look for the PA from the outside in.
* For each component instance, handle inherited properties based on subclause inheritance ordering
* @param propertyName
* @param ci the component instance whose subclause property section we are looking for the property
* @param target
* @param ciStack stack of CIS that are down the hierarchy towards the target emv2 subclause
* @param ts
* @return
*/
private static List<EMV2PropertyAssociation> getPropertyInInstanceHierarchy(String propertyName,
ComponentInstance ci, NamedElement target, Stack<NamedElement> ciStack, ErrorTypes ts) {
if (ci != null) {
if (ci.getContainingComponentInstance() != null) {
ciStack.push(ci);
List<EMV2PropertyAssociation> result = getPropertyInInstanceHierarchy(propertyName,
ci.getContainingComponentInstance(), target, ciStack, ts);
ciStack.pop();
if (!result.isEmpty()) {
return result;
}
}
// deals with inherited properties by walking subclause inheritance
List<ErrorModelSubclause> emslist = EMV2Util.getAllContainingClassifierEMV2Subclauses(ci);
for (ErrorModelSubclause ems : emslist) {
List<EMV2PropertyAssociation> props = ems.getProperties();
List<EMV2PropertyAssociation> result = getMatchingPropertiesInList(props, propertyName, target, ciStack,
ts);
if (!result.isEmpty()) {
return result;
}
}
}
return Collections.emptyList();
}
/**
* retrieve an error model property (such as Hazard) attached to an error model element based on contained property associations
* in the annex subclause properties section.
* Here we come down the component instance hierarchy to find the outmost property association
* in the properties section of the annex subclauses. Those are the ones that can override down the component hierarchy.
* @param propertyName name of property we are looking for
* @param ci component instance whose EM element has the property
* @param target the error model element (which is optionally followed by a type that is contained in the typeset ts
* @param ts the type set
* @return Containmentpath of the PA that matches the parameters.
* we return the path because the PA applies to more than element
*/
public static List<EMV2PropertyAssociation> getPropertyInInstanceHierarchy(String propertyName, NamedElement ci,
NamedElement target, ErrorTypes ts) {
if (ci == null) {
return Collections.emptyList();
}
Stack<NamedElement> ciStack = new Stack<NamedElement>();
ComponentClassifier cl = null;
if (ci instanceof ComponentInstance) {
// ciStack will contain the nested set of component instances
return getPropertyInInstanceHierarchy(propertyName, (ComponentInstance) ci, target, ciStack, ts);
}
if (ci instanceof Subcomponent) {
// look in enclosing component impl first. Then in classifier of subcomponent
cl = (ComponentClassifier) ((Subcomponent) ci).getContainingClassifier();
ciStack.push(ci);
// ciStack has subcomponent whose error model is of interest
List<EMV2PropertyAssociation> result = getPropertyInClassifier(propertyName, cl, target, ciStack, ts);
if (!result.isEmpty()) {
return result;
}
ciStack.pop();
cl = ((Subcomponent) ci).getAllClassifier();
return getPropertyInClassifier(propertyName, cl, target, ciStack, ts);
}
if (ci instanceof ComponentClassifier) {
cl = (ComponentClassifier) ci;
// empty ciStack
return getPropertyInClassifier(propertyName, cl, target, ciStack, ts);
}
return Collections.emptyList();
}
/**
* retrieve an error model property (such as Hazard) attached to an error model element based on contained property associations
* in the annex subclause properties section of the classifier.
* @param propertyName name of property we are looking for
* @param ci component instance whose EM element has the property
* @param target the error model element (which is optionally followed by a type that is contained in the typeset ts
* @param ts the type set
* @return Containmentpath of the PA that matches the parameters.
* we return the path because the PA applies to more than element
*/
public static List<EMV2PropertyAssociation> getPropertyInClassifier(String propertyName, Classifier cl,
NamedElement target, Stack<NamedElement> ciStack, ErrorTypes ts) {
if (cl != null) {
// deals with inherited properties by walking subclause inheritance
EList<ErrorModelSubclause> emslist = EMV2Util.getAllContainingClassifierEMV2Subclauses(cl);
for (ErrorModelSubclause ems : emslist) {
List<EMV2PropertyAssociation> props = ems.getProperties();
List<EMV2PropertyAssociation> result = getMatchingPropertiesInList(props, propertyName, target, ciStack,
ts);
if (!result.isEmpty()) {
return result;
}
}
}
return Collections.emptyList();
}
/**
* get Severity
* @param ci component instance, subcomponent, or classifier
* @param target Error Model element
* @param ts Typeset
* @return path to element with property
*/
public static List<EMV2PropertyAssociation> getSeverityProperty(NamedElement ci, NamedElement target,
ErrorTypes ts) {
return EMV2Properties.getProperty("EMV2::Severity", ci, target, ts);
}
/**
* get likelihood
* @param ci component instance, subcomponent, or classifier
* @param target Error Model element
* @param ts Typeset
* @return path to element with property
*/
public static List<EMV2PropertyAssociation> getLikelihoodProperty(NamedElement ci, NamedElement target,
ErrorTypes ts) {
return EMV2Properties.getProperty("EMV2::Likelihood", ci, target, ts);
}
public static NamedElement getPropagationElement(ErrorPropagation errorPropagation) {
return errorPropagation.getFeatureorPPRef().getFeatureorPP();
}
}