${jboss.bind.address.management:127.0.0.1}
Expressions are mechanism that enables you to support variables in your attributes, for instance when you want that value of attribute is resolved using system / environment properties.
an example for expression is this:
${jboss.bind.address.management:127.0.0.1}
which means that value should be taken from system propertey named jboss.bind.address.management and if it is not defined use 127.0.0.1
system properties (summary of predefined system properties can be found here)
environment properties, prefixed with env.
The easiest way is by using AttributeDefinition that provides support for expression just just by using it right.
when we create AttributeDefinition all we need to do is mark that is allows expression. Here is an example how to define an attribute that allows expressions to be used.
SimpleAttributeDefinition MY_ATTRIBUTE = new SimpleAttributeDefinitionBuilder("my-attribute", ModelType.INT, true) .setAllowExpression(true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setDefaultValue(new ModelNode(1)) .build();
Then later when you are parsing the xml configuration you should use attribute definition to set value to model.
.... String attr = reader.getAttributeLocalName(i); String value = reader.getAttributeValue(i); if (attr.equals("my-attribute")) { MY_ATTRIBUTE.parseAndSetParameter(value, operation, reader); } else if (attr.equals("suffix")) { .....
Note that this just helps you properly set the value to the model node you are working on, so no need to additionally set anything to the model for this attribute. Method parseAndSetParameter parses the value that was read from xml for possible expressions in it and if it finds it it creates special model node that defines that node is of type expression.
Later in your operation handlers where you implement populateModel and have to set model you also use this attribute definition.
@Override protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { MY_ATTRIBUTE.validateAndSet(operation,model); }
This will make sure that attribute that is passed to operation is valid and nothing is lost and also that default values are used.
As last step we need to use the value of the attribute? This is usually needed inside of the performRuntime method
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException { .... final int attributeValue = MY_ATTRIBUTE.resolveModelAttribute(context, model).asInt(); ... }
As you can see resolving of attribute's value is not done until it is needed, that way we do not loose any information in the model and can assure that also marshalling is done properly, where we must marshall back the unresolved value.
Attribute definitinon also helps you with that:
public void writeContent(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException { .... MY_ATTRIBUTE.marshallAsAttribute(sessionData, writer); MY_OTHER_ATTRIBUTE.marshallAsElement(sessionData, false, writer); ... }