ResourcePatterns can be used to create particular ensembles of Resources, and to register listeners for them. In its most basic incarnation, a ResourcePattern consists of a primary Resource type, the 'demanded model', which has to be specified as a Generics parameter, and additional subresources. An example could look like this:
The model variable represents the demanded model here, of type CoolingDevice. If we were to create resources based on this pattern, a toplevel CoolingDevice would be created, as well as the three subresources. On the other hand, if we registered a pattern demand for this pattern, we would receive a patternAvailable() callback for all active resources of type CoolingDevice, which possess the indicated subresources (they must be active as well). A CoolingDevice which only has a temperature sensor, but no control limits would not trigger a callback.
Resource Pattern Demand
We can use PatternListeners to get informed about all appearing and disappearing Resource patterns that match our registered pattern class. A PatternListener should be thought of as an enhanced version of a ResourceDemandListener; it enables us to specify further conditions on a resource in order for a callback to be triggered, such as the existence of certain subresources. Theses conditions are defined by means of the pattern fields.
A PatternListener must implement the two methods patternAvailable() and patternUnavailable():
Register your listener with the
addPatternDemand() method of the ResourcePatternAccess (see Working with OGEMA Resources#OGEMAservicesforResourceaccess), as in the following example:
Here rpa is the ResourcePatternAccess object obtained from the ApplicationManager. The third parameter specifies the AccessPriority for the resources requested by the pattern demand (see Working with OGEMA Resources#ReadingandWritingResourcevalues). Remember to deactivate your demand in the Application.stop() method.
The accept() method
Often there are additional constraints on the Resource patterns that need to be satisfied before we want to receive a callback. For instance, we might ask that the value of a subresource isControllable() of type BooleanResource is true. Much more complex filters may occur as well. For this purpose, ResourcePatterns can define an individual filter by overriding the accept() method of the generic ResourcePattern class, which has a boolean return value. A pattern only triggers a callback if it is complete, and the accept() method return true. So, let's add one to our example from above:
How can we tell the framework to re-check the accept()-condition upon value changes of a resource? Simply add an annotation to the respective resource in the pattern:
It may also happen that the custom filter depends on optional subresources, i.e. subresources which must not necessarily exist for the pattern to be considered complete, but which influence the filter. We can declare such subresources as optional elements in the pattern:
This will trigger repeated checks of the accept()-Method whenever the controllable() subresource is activated or deactivated (or created/deleted). We could also add a ValueChangedListener to this subresource, in order to trigger execution of the filter method on value changes of the controllable resource.
Create and activate Patterns
Patterns can be used to create Resources (ResourcePatternAccess.
in which case a toplevel Resource is created of the type specified as demanded model in the pattern, as well as the subresources specified in the pattern. Optional entries are not created, and the accept()-Method is not evaluated.
Note that just like Resource#create, the the create-Method for patterns does not activate the resources. In order to activate all resource-fields of a pattern, call
Pattern listeners only receive callbacks for active patterns (i.e. the model resource and all non-optional fields must be active).
(available from version 2.1.0 onwards)
A PatternChangeListener can be registered for individual pattern matches (but also pattern instances that aren't "matches", i.e. which do not satisfy all of the pattern conditions), and reports changes in any of the pattern's fields which are annotated by a @ChangeListener annotation. The annotation can be configured individually to report value and/or structure changes.Just like the PatternListener should be thought of as an enhanced version of the ResourceDemandListener, a PatternChangeListener is an enhanced version of both ResourceStructureListener and ResourceValueListener. An additional aspect of the PatternChangeListener is, that it reports all modifications made in a single transaction (see Resource Transactions) in a single callback, therefore reducing the number of callbacks that need to be processed. Its callback method
hence receives a list of events.
An example pattern class for use with a PatternChangedListener could look like this:
The corresponding listener and its registration could look like this:
Another typical usage would be to register a PatternListener for patterns of a specific type, and to add a PatternChangeListener for all matches found in the PatternListener's patternAvailable() method.
The following annotations can be used on fields of a ResourcePattern:
Debugging Pattern demands (>= v2.0.5)
If you have registered a pattern demand in your application, you can display the full matches and the incomplete ones (matching model resource, but some other condition not satisfied) in the OGEMA console, through the command
Furthermore, the demokit comes with a graphical tool that displays the same information (pattern-debugger).