5.6 Manipulating Property Values
This section describes some specific issues in the use of PropertyValue objects, particularly in the use of IntegerValue and RealValue objects.
The attributes of PropertyValue objects can be changed using the attribute setter methods. Changing the values of the PropertyValue objects obtained from the property lookup methods, however, may not have the intended affects on the model. Because the property lookup methods handle searching the component hierarchies, interpreting references to property constants, interpreting references to other property values, and evaluating Boolean expressions, the PropertyValue objects obtained from the lookup may be located in surprising locations in the model, and it is possible they may be freshly created objects and not located in the model at all. To change the value of a property it is best to create a new PropertyValue object to use with setPropertyValue. For example, the following code segment increments an integer property value associated with a particular component:
final IntegerValue iv = (IntegerValue) ph.getPropertyValue(pd);
if (iv != null) {
IntegerValue iv2 = PropertyFactory.eINSTANCE.createIntegerValue();
iv2.setNewValue(iv.getValue() + 1);
ph.setPropertyValue(pd, iv2);
(We assume pd refers to a property definition of type aadlinteger.)
5.6.1 Copying PropertyValues
Sometimes you want to copy a property value from one property association to another. You might be tempted to use the property value objects returned by a property lookup method and feed them back to setPropertyValue, as shown below:
// Anti-pattern for copying property values
final List val = ph.getPropertyValueList(pd_propA);
// Do not do this!
ph.setPropertyValue(pd_propB, val);
Do not do this. This can have unexpected effects on the model because it can cause a PropertyValue object to have a new containing object the meta model, and thus destroy the original property association. Instead, you should create a copy of the property value objects and set the new the property value using the copies:
// Pattern for copying property values
final List val = ph.getPropertyValueList(pd_propA);
// Do this instead
final List valCopy = AadlUtil.copyList(val);
ph.setPropertyValue(pd_propB, valCopy);
The static method AadlUtil.copyList(List) takes a List of EObject references and returns a new List object whose contents are copies of the objects in the original list, in the same order. Any references shared among the objects in the list are also shared among objects in the copied list. The copying is performed using the method EcoreUtil.copy(EObject), which deep-copies an individual model object. These copying methods are useful for copying model structure generally, but we cover them here because we have found them most useful when manipulating property values.
Also, IntegerValue and RealValue (via the superclass NumberValue) contain the methods cloneNumber() and cloneAndInvert(). The first method returns a copy of the number. The second returns a copy that has the inverse value.
5.6.2 Unparsing Property Values
To get the string representation of a property value, use the method PropertyValue.getValueAsString().
5.6.3 Using Range Values
The AADL specification allows the minimum, maximum, and delta components of the range to be specified using either literals or references to property constants. Thus, in the meta model, the minimum, maximum, and delta attributes of RangeValue contain NumberOrPropertyReference objects. You can get the value of a NumberOrPropertyReference object using getNumberValue(). We have added three convenience methods to RangeValue to provide direct access to the numeric values of its attributes: getMinimumValue(), getMaximumValue(), and getDeltaValue(). All three methods return a NumberValue.
5.6.4 Getting Type Literals
Given a UnitsType object, the member UnitLiteral objects can be retrieved by name using the method UnitsType.findUnitLiteral(String unitName). If no literal with the given name exists the method returns null.
Similarly, the method EnumType.findEnumLiteral(String litName) looks for the named enumeration literal in the given enumeration type, and returns null if the literal is not found.
5.6.5 Scaling Number Values
As described in Section 5.2.1 AADL Property Types, aadlreal and aadlinteger property types can specify that their values have units. In the meta model, this is captured by the unitLiteral attribute of NumberValue. However, the value attribute of RealValue and IntegerValue is maintained separately from unitLiteral. It is thus the case that interpreting the actual value represented by a RealValue or IntegerValue involves checking the values of two attributes, as well as interpreting the value of the unit literal itself relative to the other unit literals in its UnitType.
OSATE shields the plug-in programmer from this tedious process via the methods NumberValue.getScaledValue() and NumberValue.getScaledValue(UnitLiteral). Both methods return a double value: the first returns the value scaled relative to the base unit of the number’s UnitsType; the second method returns the value scaled relative to the given UnitLiteral, which must be from the number’s UnitsType.
For example, consider the IntegerValue representing the AADL property expression 30 foot of type Example::Length. Method getScaledValue() returns 360.0, the value scaled to the base unit inch. Invoking the parameterized method with the UnitLiteral object representing the unit yard returns 10.0. Thus, given a PropertyHolder object ph representing a component whose Example::Documentation_Thickness property has value 30 foot, executing the following segment of code
final UnitsType units =
(UnitsType) OsateResourceManager.findPropertyType(
"Example", "English_Units");
final IntegerValue iv =
(IntegerValue) ph.getSimplePropertyValue(
"Example", "Documentation_Thickness");
System.out.println("Scaled Value: " + iv.getScaledValue());
System.out.println("In Yards: " +
iv.getScaledValue(units.findUnitLiteral("yard")));
results in the following console output:
Scaled Value: 360.0
In Yards: 10.0
5.6.6 Setting Number Values
The class NumberValue contains the attribute valueString which shadows the value of the value attribute of RealValue and IntegerValue. This attribute is maintained so that the number value can be unparsed to the same syntactic form from which it was parsed. This is important because AADL allows integer values to be denoted in bases other than ten, allows exponential notation for real values, and allows underscores to be inserted between numerals. These syntactic features are often important to the readability of specifications, and thus it is separately maintained in the valueString attribute.
As a consequence, when the value attribute of a NumberValue is changed, the valueString attribute should also be. Because it is inconvenient, and error prone, to expect that setValueString be invoked every time setValue is invoked, NumberValue also features the method setNewValue(Number) which simultaneously updates both the value and valueString attributes. Class RealValue has the more specific method setNewValue(double), and class IntegerValue has the more specific method setNewValue(long). Because integer values may be denoted in bases other than ten, IntegerValue also has the method setNewValue(long value, int base), which allows the base that the string representation should be in to be specified. If the base is not a value between two and sixteen inclusive, base ten is used.
We do not offer any methods for controlling how a real value is represented as a string; the setValueString method can be used in conjunction with the java.text.DecimalFormat class to exercise finer control over the unparsing of RealValue objects.
The unit literal for a number value, if one is desired, is set by the setUnitLiteral method.
As an example, executing the code segment
final UnitsType units =
(UnitsType) OsateResourceManager.findPropertyType(
"Example", "English_Units");
final IntegerValue iv2 =
PropertyFactory.eINSTANCE.createIntegerValue();
iv2.setNewValue(18L);
iv2.setUnitLiteral(units.findUnitLiteral("inch"));
System.out.println("New value: " + iv2.getValueAsString());
System.out.println("valueString: " + iv2.getValueString());
System.out.println("Scaled Value: " + iv2.getScaledValue());
System.out.println("In Feet: " +
iv2.getScaledValue(units.findUnitLiteral("foot")));
results in the following console output.
New value: 18 inch
valueString: 18
Scaled Value: 18.0
In Feet: 1.5