Class Trouble
- Indication of a problem. For example, if a piece of hardware is missing a trouble can be used to indicate this error.
- Action required. A trouble can set the
resolveable
flag which indicates an action that needs to be performed and then simply resolving the trouble can cause the action to be performed without the caller needing to know how to perform the action. For example, if a pump needs to be primed, a trouble can be created that will prime the pump when resolved. - Indication of state. For example, if the user is supposed to clean the device periodically, a trouble can be used to display a reminder. By making the trouble resolvable with no action, the user can dismiss the reminder by simply resolving the trouble.
TroubleAware
then the object will receive events
related to the trouble. However, impacted objects are included in
equality whereas linked objects are not.
The purpose of impacted is to make two instances of the same trouble equal if they impact the same objects but not equal if they impact different object. Since it is common to generate multiple troubles of the same type over time, equality is used to ignore troubles that are already known. By using the impact list for equality it typically avoids the need for subclasses to define equals. In fact, care must be taken when redefining equals in subclasses as it must be very selective to maintain pruning of duplicate troubles. Examples of objects that are commonly added to the impact list are containers, pumps, holders, boards, and so on.
The purpose of the linked object list is to allow objects to be associated with the trouble which can be used for other processes. For example, if a service creates a trouble, it can add the service to the linked list and later remove all troubles linked to the service without needing to maintain references to the troubles.
The impact list cannot be added to once the trouble is added to the trouble service while the linked list can be modified at any time.
Troubles also have a concept of string tags. Tags will be exposed via endpoints and an be used to convey information about the trouble to external code such as a ui. For example consider a prime trouble which indicates a pump should be primed. When an ingredient is inserted it may create a prime trouble to make the ingredient healthy. Separately there may be a service that creates prime troubles if an ingredient hasn't been poured in a certain number of days. These troubles can have a tag to indicate they are the result of inactivity and the ui has the choice of displaying them different. This avoids the need to create a new type of trouble just to pass a hint to the ui.
Troubles can contain one or more ifaces. An iface is a symbolic name for a logical data interface provided by the trouble. Many troubles return similar data (holders, containers, pumps, etc...) and as each trouble is created there can be subtle variations that make external integrations, such as ui's, very difficult to write. An iface is a hint in the payload that tells the integration that it can expect certain pieces of data to exist with specific semantics. This also protects external code from a new trouble being created that happens to use a property name that is typically used in a different way. Integrations can see the iface is not in the list and assume the property does not contain the expected data.
As mentioned above, equality of troubles is very important as duplicate troubles cannot be added to the trouble list. The base Trouble class only compares class and impacted objects for equality. For subclasses it is important to consider what additional fields should be considered with regard to equality as it is rarely correct to simply include all fields. For example, consider a trouble that indicates an underflow on a pumps and it records the underflow rate for analytics. If the rate is included in equals, a pump may generate dozens of underflow troubles when there is really just one underlying issue. Troubles are logged even if duplicate so analytics can still see the occurrence but the actual list shown to the user would only reflect one trouble.
When serialized to json, troubles are generally restricted to one of the following views:
- Trouble.View.class
- Trouble.Debug.class extends Trouble.View.class
- Since:
- 1.0
- Version:
- 2022-09-17
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interface
JsonView to expose data via troubles endpoints. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoid
Add a symbolic interface name to the trouble.void
addImpacted
(Object obj) Add an object to the impact list.void
Link an object to the troublevoid
Add a tag to the troubleboolean
int
getCount()
TroubleService
doesn't allow duplicate troubles to be added (based on object equality).getGroup()
int
getId()
getInfo()
getTags()
getType()
Return the type of the trouble which is the simple class name.int
hashCode()
void
incCount()
Increment the count for the trouble.boolean
isImpacted
(Object obj) Return true if the specified object is in the impact list.boolean
Return true if the specified object is linked to the trouble.boolean
Return true if the trouble is resolvable.boolean
Return true if the specified string is in the tag list.void
Called when a trouble is removed fromTroubleService
.void
removeImpacted
(Object obj) Remove an object from the impact list.void
removeLink
(Object obj) Remove a linked object from the troublevoid
Remove a tag from the troublevoid
Indicate that the trouble is resolvable.resolve()
If resolvable, return the work to perform to potentially resolve the underlying problem that caused the trouble.setResolvable
(boolean resolvable) toString()
-
Constructor Details
-
Trouble
public Trouble()
-
-
Method Details
-
getType
Return the type of the trouble which is the simple class name. -
addIface
Add a symbolic interface name to the trouble. This is to indicate to external systems that they can expect certain data to exist in the trouble. For example, an external system may want to gather all troubles that relate to a board using the handle path to the impacted board. Rather than checking every trouble for board path, the related troubles can add an interface name to indicate it is board related. This also allows other troubles that happen to include a board path, but are not actually troubles about the board to not be accidentally grouped by the external system.The most common pattern is for a base Trouble subclass to add the interface names and associated data so subclasses get the functionality automatically.
Another common pattern is for troubles that don't share a common base class but share common data (such as including board path to indicate the board that is impacted) to add the same interface so the data appears consistent to external systems like ui code.
- Parameters:
iface
- the subType to add
-
addLink
Link an object to the trouble- Parameters:
obj
- the object to link
-
removeLink
Remove a linked object from the trouble- Parameters:
obj
- the linked object to remove
-
isLinked
Return true if the specified object is linked to the trouble. -
addTag
Add a tag to the trouble- Parameters:
tag
- the tag to add
-
removeTag
Remove a tag from the trouble- Parameters:
tag
- the tag to remove
-
isTagged
Return true if the specified string is in the tag list. -
addImpacted
Add an object to the impact list. The impact list is used for equality so be aware of how the impact list is used in the case duplicate troubles are expected.- Parameters:
obj
- the impacted object
-
removeImpacted
Remove an object from the impact list. The impact list is used for equality so be aware of how the impact list is used in the case duplicate troubles are expected.- Parameters:
obj
- the object to remove
-
isImpacted
Return true if the specified object is in the impact list. -
isResolvable
public boolean isResolvable()Return true if the trouble is resolvable. This must always return the same value over the life of the trouble. -
resolvable
public void resolvable()Indicate that the trouble is resolvable. This should be called in the trouble constructor to indicate that the trouble can perform an action by callingresolve()
. -
getCount
public int getCount()TroubleService
doesn't allow duplicate troubles to be added (based on object equality). This means that if a trouble that it equal to an existing trouble is added, the new trouble will be ignored. However,TroubleService
will bump the count on the existing trouble to reflect that another equal trouble was added. The count cannot be part of equality as it would cause troubles that are otherwise equal to no longer be equal. The count is also not reflected in the json view of the object as troubles are not re-broadcast when the count changes.This is a useful way to determine how many troubles of a given type have occurred without requiring external counters.
-
incCount
public void incCount()Increment the count for the trouble. This is called when another trouble that is equal to this is added viaaddTrouble()
. This can be called externally in the event that a service would have created an equal trouble and needs to record that in the count, but wants to avoid creating the trouble simply to increment. -
resolve
If resolvable, return the work to perform to potentially resolve the underlying problem that caused the trouble. If the work completes successfully then the trouble will be removed, otherwise it will remain in the list and continue to be resolvable. If this trouble returns true for isResolvable() it must return a valid work from this method.- Returns:
- the work to resolve the trouble
-
onRemoved
public void onRemoved()Called when a trouble is removed fromTroubleService
. This can be used to perform some final cleanup associated with the trouble. -
getId
public int getId() -
getImpacted
-
getLinked
-
getTags
-
getIfaces
-
getCreateTime
-
getInfo
-
getReason
-
getClientData
-
getGroup
-
toString
-
equals
-
hashCode
public int hashCode() -
setReason
- Returns:
this
.
-
setResolvable
- Returns:
this
.
-