(Click to open topic with navigation)
Plugins may easily create new events and create or update notification conditions using the Plugin Event Service. Previously, this was only possible by utilizing the MWS REST resources. The event service eases this burden from plugin developers. There are several operations that are available using the service:
Events are composed of several properties such as arguments, associated objects, origin, message, severity, escalation level, and a unique event code. The plugin event service removes the need for magic strings such as those for event severity ("INFO", "WARN", "FATAL") and also handles creating unique event codes. In other words, no bitwise manipulation is required to create new events.
The event code is comprised of several elements:
Code element | Description |
---|---|
Severity | If the event is informational, a warning, an error, or fatal. |
Escalation level | Who cares about the event, or who should act on the event. |
Component code | Internally made up of the MWS component code (stored internally) and the plugin event component code (see Plugin event component code). |
Entry code | The code representing a unique event for the component (for each plugin event component code). |
The plugin event service handles the severity, escalation level, and entry code portions of the code by the values passed as parameters to the createEvent method. The plugin event component code is described in the next section.
The plugin event component code should be a unique number across all plugin types or projects from 1-254. This number is combined with the MWS component code to represent each plugin as a unique component code across all Adaptive Computing products. 0 is reserved for MWS itself and should not be used. 255 is reserved for plugin types that do not define an event component code and represents an "unknown" plugin component. Additionally, codes 1-150 are reserved for Adaptive Computing plugins, while 151-254 are reserved for Professional Services and/or customer-specific plugins.
This code may be specified by setting an eventComponent property (see Fields: Plugin Types) on the plugin project file or as a static property on the plugin type. As with all other project properties, the plugin type value overrides the project value. For example:
class MyExampleProject { … Integer eventComponent = 2 … } ExamplePlugin { static final eventComponent = 1 … } Example2Plugin { // no eventComponent property … }
In this case, the plugin type ExamplePlugin has a plugin event component code of 1, while the Example2Plugin has a code of 2 since it inherits it from the project properties.
Origin suffix
The origin of an event created through the plugin event service is automatically set by the plugin framework to MWS/plugins/<plugin type>/<plugin id>. For example, an event created by the plugin created from the "ExamplePlugin" plugin type with an ID of "plugin1" would generate events with an origin of MWS/plugins/Example/plugin1.
While this origin is sufficient for an administrator to determine the plugin where the event came from, the plugin developer may want this to be more specific to a class name or method name. This may be done using the optional originSuffix parameter to the createEvent method. The origin suffix, as its name implies, is appended to the end of the generated origin. For the example above, suppose the plugin developer passed myMethod/switch1 as the origin suffix parameter when creating a new event. The event would then have an origin of MWS/plugins/Example/plugin1/myMethod/switch1.
Event enumerations
While creating events using the plugin event service is quite simple, often there are related events that have properties in common, such as the event type prefix or the origin suffix. Additionally, i18n messages (see i18n Messaging) are typically used for the event's message. Using the EventEnumeration annotation (see Plugin Event Service) in combination with a enumeration simplifies this process. When this is done, each message is pulled from the messages.properties files using a standard convention, and the event type prefix and the origin suffix may optionally added as static properties on the enumeration. Using EventEnumeration requires:
If any of these conditions are not fulfilled, using the EventEnumeration annotation will result in compilation errors.
Enumeration values are automatically marked as implementing the IPluginEvent interface and may be used as the first parameter of the createEvent method on the plugin event service. For example:
package example import com.adaptc.mws.plugins.EventEnumeration import com.adaptc.mws.plugins.IPluginEventService.AssociatedObject import static com.adaptc.mws.plugins.IPluginEventService.Severity.* import static com.adaptc.mws.plugins.IPluginEventService.EscalationLevel.* public class ExamplePlugin { void poll() { // Event 1 takes no arguments pluginEventService.createEvent(ExampleEvents.EVENT1, null, null) // Event 2 takes one argument and has an associated object pluginEventService.createEvent(ExampleEvents.EVENT2, ["arg1"], [new AssociatedObject(type:"type1", id:"id1")]) } } @EventEnumeration enum ExampleEvents { EVENT1("Example One", INFO, USER), // Entry code is 0 EVENT2("Example Two", INFO, USER) // Entry code is 1 }
It may be noted that several key properties of events are missing from the enumeration definition and create event call parameters:
Messages for event enumerations
The message for events created from enumerations is generated using i18n messages (see i18n Messaging) with codes in the following format:
Considering the example in the section above, the message for ExampleEvents.EVENT1 would be generated using the argument list passed to the createEvent method with the "ExampleEvents.EVENT1.message" message from messages.properties. This message should contain arguments if needed, such as "My example with ID {0} was created" and is used as the "message" property in the created event. The comment, on the other hand, is not persisted with the event and should be text (typically in paragraph format) describing why the event typically occurs or what actions should be taken when it does occur. Consider the message to contain instance specific information for the event (passed as arguments to the message) and the comment to be general documentation concerning the event.
As a best practice, name event enumeration values using the number and short name of each argument to the message. This makes it easy for the consumer to know which arguments are expected and what each means. For example, if an event is for connection errors and needs two arguments to the message, the URL and the error message, the enumeration value should be named "CONNECT_FAILURE_1URL_2ERROR" or even "CONNECT_TO_1URL_FAILURE_2ERROR". In this way, the consumer knows that the first argument represents the URL and the second is the error message.
Event type for event enumerations
As described above, the static string field EVENT_TYPE_PREFIX may be defined on the enumeration. This value is optional and, when present, is prepended with a space to the event name parameter from the constructor to generate the event type. For example, consider the following enumeration:
package example import com.adaptc.mws.plugins.EventEnumeration import static com.adaptc.mws.plugins.IPluginEventService.Severity.* import static com.adaptc.mws.plugins.IPluginEventService.EscalationLevel.* @EventEnumeration enum MyPluginEvents { CONNECT("Connect", INFO, ADMIN), DISCONNECT("Disconnect", INFO, ADMIN) static String EVENT_TYPE_PREFIX = "My Plugin" }
If MyPluginEvents.CONNECT and MyPluginEvents.DISCONNECT were used with the plugin event service, the generated event types would be "My Plugin Connect" and "My Plugin Disconnect" respectively.
Origin for event enumerations
The origin for event enumeration values automatically contains more information than those for non-enumerated events, such as those described above. The enumeration type name and value are appended to the origin. For example, consider the following enumeration and plugin fragment:
… class ExamplePlugin { … assert id=="example1" // plugin ID is example1 pluginEventService.createEvent(ExampleEvents.EVENT1, null, null) … } … @EventEnumeration enum ExampleEvents { EVENT1("Event One", INFO, ADMIN) ...
The origin generated for the created event would be MWS/plugins/Example/example1/ExampleEvents/EVENT1. The static string field ORIGIN_SUFFIX may also be defined on the enumeration. This value is optional and, when present, is appended to the end of the generated origin as described above with the origin suffix parameter to the createEvent method.
Example
In order to understand all interactions when event enumerations are used, the following is a complete example.
Plugin type ------------------------------------ package example import com.adaptc.mws.plugins.* class ConnectPlugin extends AbstractPlugin { static eventComponent = 1 IPluginEventService pluginEventService void poll() { def errorMessage = connect() if (errorMessage) pluginEventService.createEvent(ConnectEvents.CONNECT_TO_1URL_FAILURE_2ERROR, [config.url, errorMessage], null) else pluginEventService.createEvent(ConnectEvents.CONNECT_SUCCESS, null, null) } // Returns the error message or null/empty on success private String connect() { String errorMessage … return errorMessage } }
Event enumeration ------------------------------------ package example import com.adaptc.mws.plugins.EventEnumeration import static com.adaptc.mws.plugins.IPluginEventService.Severity.* import static com.adaptc.mws.plugins.IPluginEventService.EscalationLevel.* @EventEnumeration enum ConnectEvents { CONNECT_SUCCESS("Success", INFO, ADMIN), CONNECT_TO_1URL_FAILURE_2ERROR("Failure", ERROR, ADMIN) static String EVENT_TYPE_PREFIX = "Connect" }
messages.properties ------------------------------------ ConnectEvents.CONNECT_SUCCESS.message=The plugin was successfully connected! ConnectEvents.CONNECT_SUCCESS.comment=This occurs when the plugin successfully connects to the configured URL and is informational only. ConnectEvents.CONNECT_TO_1URL_FAILURE_2ERROR.message=The plugin failed to connect to {0}: {1} ConnectEvents.CONNECT_TO_1URL_FAILURE_2ERROR.comment=This occurs when the plugin fails to connect to the configured URL for any reason. The most common reason is that the service is not running and needs to be started.
The following are examples of the events created in MWS:
Created events ------------------------------------ {"totalCount": 2, "resultCount": 2, "results": [ { "arguments": ["http://localhost:1000", "The service is not running!"], "code": 570523649, "eventDate": "2013-06-12 19:16:50 UTC", "eventType": "Connect Failure", "message": "The plugin failed to connect to http://localhost:1000: The service is not running!", "origin": "MWS/plugins/Connect/connect/ConnectEvents/CONNECT_TO_1URL_FAILURE_2ERROR", "severity": "ERROR", "id": "51b8c922a816c6a04af2401d", "associatedObjects": [] }, { "arguments": [], "code": 33652736, "eventDate": "2013-06-12 19:18:07 UTC", "eventType": "Connect Success", "message": "The plugin was successfully connected!", "origin": "MWS/plugins/Connect/connect/ConnectEvents/CONNECT_SUCCESS", "severity": "INFO", "id": "51b8c96fa816c6a04af24021", "associatedObjects": [] } ]}
Unique event codes
The last topic that must be covered in creating events from plugins is that all efforts should be made to make sure that event codes are unique throughout all Adaptive Computing product suites. Additionally, the codes should be static, meaning they do not change once established. In order to do this, adhere the following recommendations:
Creating or Updating Notification Conditions
The plugin event service also makes it easy to create or update notification conditions. Simply use the updateNotificationCondition method. Just as the MWS notification condition resource, this is an idempotent operation, meaning it can be called multiple times with the same result. If the notification condition does not exist, it will be created automatically. If it does exist, the observed date and details will be updated accordingly.
Examples are available on Plugin Event Service.
Related Topics