6.2.6 Configuration Constraints

Plugin types can optionally define validation constraints for the polling interval and plugin configuration. These parameters are then checked against the defined constraints during the creation of a new plugin. If the validation fails, meaning the configuration provided does not pass the constraints defined by the plugin type, the plugin will fail to be created with error messages based on the parameters and constraints defined.

Defining Constraints

To define constraints for a plugin type and therefore for all plugins created using it, use the following syntax:

import com.adaptc.mws.plugins.*
class ConstrainedPlugin extends AbstractPlugin {
	static constraints = {
		// Set plugin's default polling interval
		pollInterval defaultValue:60
		// The "myParam" configuration parameter is automatically required and 
cannot be blank
		myParam blank:false
		// The "myEnum" configuration parameter is not required and must set to 
one of the values in the list
		myEnum required:false, inList:["val1", "val2", "val3]
		// Insert additional constraints here…
	}
}

In the table below, all available constraints are shown, as well as the expected value type, an example, the default message code, and the message suffix. The message columns are described in greater detail in the Messaging section below.

Constraint Default
Value
Type Example Value Default Message Code Message Suffix Description
blank -- Boolean true default.blank.message blank If false, the parameter (if present) cannot be a blank string.
creditCard -- Boolean true default.invalid.creditCard.message creditCard.invalid

If true, uses org.apache.commons.
validator.CreditCard
Validator to determine if the parameter (if present) is a valid credit card number.

defaultValue -- Object or Closure 60 -- --

If the parameter is not present, it will be set to this default value. Does not return any error messages. See Default Value below for more information.

email -- Boolean true default.invalid.email.message email.invalid

If true, the parameter (if present) must be a valid email address.

inList -- List ["first", "second"] default.not.inlist.message not.inList The parameter (if present) must be set to one of the values specified.
matches -- String "[a-z][A-Z]+" default.doesnt.match.message matches.invalid The parameter (if present) must match the specified regular expression.
max -- Integer 10 default.invalid.max.message max.exceeded The parameter (if present) must not be greater than the defined value.
*maxSize -- Integer 10 default.invalid.max.size.message maxSize.exceeded The parameter's (if present) size must not be greater than the defined value.
min -- Integer 1 default.invalid.min.message min.notmet The parameter (if present) must not be less than the defined value.
*minSize -- Integer 1 default.invalid.min.size.message minSize.notmet The parameter's (if present) size must not be less than the defined value.
notEqual -- Object "Invalid Value" default.not.equal.message notEqual

The parameter (if present) must not be set to the defined value.

nullable true Boolean false default.null.message nullable

If true, the parameter (if present) must be non-null value. See required for how to enforce the parameter to be present.

password -- Boolean true -- --

If true, the parameter (if present) is hidden from the user both on input and display when managing plugin configuration. It is not, however, hidden in the REST API. Does not return any error messages.

range -- Range 1..10 default.invalid.range.message range.toosmall/range.toobig Uses a groovy range to validate that the value is within a specified range.
required true Boolean false default.required.message required

If true, the parameter must be present and non-null for the plugin to be created successfully. Implies the nullable:false constraint.

scale -- Integer 2 -- -- Only valid for Double parameters. Rounds the parameter (if present) to the specified number of digits. Does not return any error messages.
*size -- Range 2 default.invalid.size.message size.toosmall/size.toobig Uses a groovy range to restrict the size of a collection, string, or a number.
*type -- Class Integer.class typeMismatch typeMismatch

See Type Inferencing and Conversion below.

url -- Boolean true default.invalid.url.message url.invalid

If true, uses org.apache.commons.
validator.UrlValidator to determine if the parameter (if present) is a valid URL. Does not support exec or file scheme URLs.

scriptableUrl -- Boolean true default.invalid.scriptable.url.message scriptableUrl.invalid

Identical to the url validator but adds support for exec and file scheme URLs.

validator -- Closure (See Custom Validator) default.invalid.validator.message validator.error

See Custom Validator below.

widget -- String "textarea" -- -- By default, all strings render as a text field when creating or editing plugins. Setting this to textarea causes it to render as a text area with multi-line support. This is only valid for string configuration parameters.

* The user interface (see 6.5  Plugin Management) does not support parameters whose type is a subclass of Collection (a List, for example). Such parameters are therefore not recommended.

The polling interval constraints must always apply to Integer types. If this specification is violated, the plugin type cannot be added or updated.

Messaging

When defined constraints are violated for a plugin, error messages are retrieved based on the configuration parameters and the applied constraints using i18n Messaging codes (see 6.2.4 i18n Messaging). First, the most specific error message will be attempted to be resolved from a message code generated from the plugin type name, the configuration parameter, and the constraint. This code takes the format of pluginTypeName.parameterName.suffix where the plugin type's name has a lowercase first letter and the suffix is shown in the table above. If this message code is not defined, the default message code (as shown in the table above) will be used.

For example, if the url constraint validation failed for the ExamplePlugin plugin type's endpoint configuration parameter, the following message codes would be resolved in order:

  • examplePlugin.endpoint.url.invalid
  • default.invalid.url.message
  • Plugin types that have two or more uppercase letters at the start of the name will not be converted to have a lowercase first letter for error message codes. In other words, for the example just given using VCenterPlugin instead of ExamplePlugin, the following message codes would be resolved in order:

    VCenterPlugin.endpoint.url.invalid

    default.invalid.url.message

Default Messages

Default messages can be contained in any messages.properties file included in the plugin JAR file as explained in i18n Messaging (see 6.2.4 i18n Messaging).

Arguments for each constraint vary, but they always include these argument indices:

  • {0}: The configuration parameter name (for example, endpoint).
  • {1}: The plugin type class name (for example, my.package.ExamplePlugin).
  • {2}: The value of the configuration parameter.

If default messages are not defined in the plugin project, the following messages will be used:

default.doesnt.match.message=The ''{0}'' configuration parameter value ({2}) does not match the required pattern ''{3}''
default.invalid.url.message=The ''{0}'' configuration parameter value ({2}) is not a valid URL
default.invalid.scriptable.url.message=The ''{0}'' configuration parameter value ({2}) is not a valid scriptable URL
default.invalid.creditCard.message=The ''{0}'' configuration parameter value ({2}) is not a valid credit card number
default.invalid.email.message=The ''{0}'' configuration parameter value ({2}) is not a valid e-mail address
default.invalid.range.message=The ''{0}'' configuration parameter value ({2}) does not fall within the valid range from {3} to {4}
default.invalid.size.message=The ''{0}'' configuration parameter value ({2}) does not fall within the valid size range from {3} to {4}
default.invalid.max.message=The ''{0}'' configuration parameter value ({2}) is greater than the maximum value of {3}
default.invalid.min.message=The ''{0}'' configuration parameter value ({2}) is less than the minimum value of {3}
default.invalid.max.size.message=The ''{0}'' configuration parameter value ({2}) exceeds the maximum size of {3}
default.invalid.min.size.message=The ''{0}'' configuration parameter value ({2}) is less than the minimum size of {3}
default.invalid.validator.message=The ''{0}'' configuration parameter value ({2}) does not pass custom validation
default.not.inlist.message=The ''{0}'' configuration parameter value ({2}) is not contained within the list [{3}]
default.blank.message=The ''{0}'' configuration parameter cannot be blank
default.not.equal.message=The ''{0}'' configuration parameter value ({2}) cannot be equal to ''{3}''
default.null.message=The ''{0}'' configuration parameter cannot be null
default.required.message=The ''{0}'' configuration parameter is required and cannot be null
typeMismatch=The ''{0}'' configuration parameter value ({2}) does not match the required type ''{3}''

Labels and Help Messages

Message codes can also be provided for configuration parameters to aid the admin user with human readable property labels and help messages. Similar to the validation error message codes, labels and help message codes can be defined using the pluginTypeName.parameterName.label and pluginTypeName.parameterName.help message codes. These values are used only in plugin type management (see 6.4  Plugin Type Management) and are not exposed through the REST API.

Type Inferencing and Conversion

Due to the dynamic nature of configuration parameters, the expected type or class of values for each parameter are inferred from constraints.

The following rules govern how type is inferred, in priority order:

  • If the *type constraint is applied to a parameter, the constraint value will be used as the expected type.
  • Only the String, Date, Double, Integer, and Boolean classes are supported for the *type constraint. If Float or Long is desired, use Double and Integer respectively as the type.

  • If the inList or range constraints are applied to a parameter, the class of the first element in the constraint value array is used as the expected type.
  • If the *minSize or *maxSize constraints are applied to a parameter, java.lang.Collection is used as the expected type.
  • If the max, min, or notEqual constraints are applied to a parameter, the class of the constraint value is used as the expected type.
  • If none of the above apply, java.lang.String is used as the expected type.

If the configuration parameter values can be converted to the expected types, this will occur automatically. Otherwise, the *type constraint is violated and the applicable error messages will be generated.

Custom Validator

In cases where the built-in constraints prove inadequate for validation, custom validators can be used. The validator constraint expects a Groovy Closure parameter that has one or (optionally) two arguments: the value of the configuration parameter and the plugin object. With these parameters, complex validation logic can be defined. Additionally, custom message codes and arguments can be defined by validator constraints and these will be used in generating error messages when validation fails.

For example, suppose that the parameter 'user' cannot be set to the same value as parameter 'creator'. Additionally, the 'creator' parameter must not be equal to either bob or joe. The existing constraints are inadequate to fulfill this use case, but the following code using validators would perform exactly as expected:

import com.adaptc.mws.plugins.*
class ConstrainedPlugin extends AbstractPlugin {
	static constraints = {
		user validator:{ val, obj ->
			if (val==obj.config.creator)
				return "invalid.equal.to.creator"
		}
		creator validator:{ val ->
			if ("val"=="joe")
				return ["invalid.equal", "joe"]
			if (val=="bob")
				return ["invalid.equal", "bob"]
		}
	}
}

In the examples above, the message codes and output on validation failure is shown below:

Message codes
------------------------------------

constrainedPlugin.user.invalid.equal.to.creator=The user configuration parameter value ({2}) must not be equal to the creator parameter.
constrainedPlugin.creator.invalid.equal=The creator configuration parameter must not be equal to {3}.
Output error messages
------------------------------------

For user = "jill", creator = "jill"
"The user configuration parameter value (jill) must not be equal to the creator parameter."
For user = "jill", creator = "bob"
"The creator configuration parameter must not be equal to bob."

For user = "jill", creator = "joe"
"The creator configuration parameter must not be equal to joe."

The validator Closure may return:

  • Nothing (null) or true if the validation succeeded without errors.
  • false if a validation error occurred (in this case the default validator message suffix would be used).
  • A string that will be used as the message code suffix in the pluginTypeName.propertyName.suffix format.
  • A list with the first element being the message code suffix, and all other elements being arguments for the message indexed starting at 3 (as shown in the example above).

All validator constraints automatically have the appConfig property available, which contains the application configuration as discussed in the Configuration section (see 6.2.5 Configuration). The suite property contains the value of the configured MWS suite. Additionally, services can be retrieved as explained in the next section.

Retrieving Services

At times it may be necessary to use Bundled Services in custom validators. A method named getService, which takes a single string parameter of the name of the service (as used during injection) is provided to be used in these cases. For example, if a plugin needs a valid server certificate file, the SSL Service can be used as follows:

import com.adaptc.mws.plugins.*
class ConstrainedPlugin extends AbstractPlugin {
	static constraints = {
		certificateFile validator:{ val ->
			ISslService sslService = getService("sslService")
			try {
				sslService.getSocketFactory(val)
			} catch(Exception e) {
				// Certificate file is invalid, return an error
				return ["invalid", e.message]
			}
		}
	}
}

The getService method does not work with translators, custom components, RM services, or the Individual Datastore.

Default Value

The default value for a configuration parameter might depend on the MWS configuration or other properties. Therefore, the defaultValue constraint can be set to a closure. The defaultValue closure does not take any parameters and must return the object to be used as the default value.

For example, if the default value of a parameter must be true if and only if MWS is configured for the HPC suite, then the following constraints would satisfy these conditions:

import com.adaptc.mws.plugins.*
class ConstrainedPlugin extends AbstractPlugin {
	static constraints = {
		myParameter required: true, type: Boolean, defaultValue: {
			return suite == Suite.HPC
		}
	}
}

As with validator closures, defaultValue closures have access to appConfig, suite, and getService.