Digital Adapter
The las component that we have to implement to complete our first simple Digital Twin definition through the WLDT library is a Digital Adapter in charge of:
- Receiving event from the DT’s Core related to the variation of properties, events, available actions and relationships
- Expose received information to the external world according to its implementation and the supported protocol
- Handle incoming digital action and forward them to the Core in order to be validated and processed by the Shadowing Function
The basic library class that we are going to extend is called DigitalAdapter
and creating a new class
named DemoDigitalAdapter
. The DigitalTwinAdapter class can take as Generic Type the type of Configuration used to configure its behaviours.
In this simplified example we are defining a DigitalAdapter without any Configuration.
A Digital Adapter has direct access to the current DT’s State through callbacks or directly in a synchronous way using the
internal variable called: digitalTwinState
. Through it is possibile to navigate all the fields currently composing the state of our Digital Twin.
The Digital Adapter class has e long list of callback and notification method to allow the adapter to be updated about all the variation and changes on the twin. Available callbacks can be summarized as follows:
- Digital Adapter Start/Stop:
onAdapterStart()
: Feedback when the Digital Adapter correctly startsonAdapterStop()
: Feedback when the Digital Adapter has been stopped
- Digital Twin Life Cycle Notifications:
onDigitalTwinCreate()
: The DT has been createdonDigitalTwinStart()
: The DT startedonDigitalTwinSync(IDigitalTwinState digitalTwinState)
: The DT is Synchronized with its physical counterpart. The current DigitalTwinState is passed as parameter to allow the Digital Adapter to know the current state and consequently implement its behaviouronDigitalTwinUnSync(IDigitalTwinState digitalTwinState)
: The DT is not synchronized anymore with its physical counterpart. The last current DigitalTwinState is passed as parameter to allow the Digital Adapter to know the last state and consequently implement its behaviouronDigitalTwinStop()
: The DT is stoppedonDigitalTwinDestroy()
: The DT has been destroyed and the application stopped
The Digital Adapter DT State variations and DT events are received by the Adapter from the DT core belongs to the following categories:
- Digital Twin State Update through the method
onStateUpdate(...)
providing information about the new state of the Digital Twin, the previous state, and a list of changes that occurred between these two states. In the previous version each variation of a property, relationships, actions or events were notified. In the new version only a committed DT’State variation is notified to listeners. - Event Notifications through the method
onEventNotificationReceived(...)
whenever there is a notification about an event related to the Digital Twin’s state coming from the physical world, generated by the twin and processed by the Shadowing Function. For example in the DT State we can have the declaration of theover-heating-alert
structured and received in the DT State while the effective occurrence of the event and the associated notification is notified through this dedicated callback
The onStateUpdate
method is an abstract method that must be implemented by any class extending the DigitalAdapter
class.
This method is called whenever there is an update to the Digital Twin’s state. It provides information about the new state of the Digital Twin,
the previous state, and a list of changes that occurred between these two states.
The explanation of the parameters is the following:
newDigitalTwinState
: This parameter represents the updated state of the Digital Twin. It is an instance of theDigitalTwinState
class, which encapsulates the current state information.previousDigitalTwinState
: This parameter represents the state of the Digital Twin before the update. It is also an instance of theDigitalTwinState
class.digitalTwinStateChangeList
: This parameter is anArrayList
containingDigitalTwinStateChange
objects. EachDigitalTwinStateChange
object encapsulates information about a specific change that occurred between the previous and new states. It includes details such as the property or aspect of the state that changed, the previous value, and the new value.
Another core method where a Digital Adapter receive the description of the DT’State is onDigitalTwinSync(IDigitalTwinState digitalTwinState)
.
The Adapter using the parameter digitalTwinState
can analyze available properties, actions, events and relationships and decide how to implement its internal behaviour with the methods presented in ShadowingFunction.
The DT State is automatically monitored by each Digital Adapter while for the Events potentially generated by the DT can be observed by each adapter using:
observeAllDigitalTwinEventsNotifications
: Enable the observation of available Digital Twin State Events Notifications.unObserveAllDigitalTwinEventsNotifications
: Cancel the observation of Digital Twin State Events NotificationsobserveDigitalTwinEventsNotifications
: Enable the observation of the notification associated to a specific list of Digital Twin State events. With respect to event a notification contains the new associated valueunObserveDigitalTwinEventsNotifications
: Cancel the observation of a target list of propertiesobserveDigitalTwinEventNotification
: Enable the observation of the notification associated to a single Digital Twin State event. With respect to event a notification contains the new associated valueunObserveDigitalTwinEventNotification
: Cancel the observation of a single target event
The resulting code will be the following after adding the required methods (still empty) and the basic constructor with the id String parameter is the following:
import it.wldt.adapter.digital.DigitalAdapter;
import it.wldt.core.state.*;
public class DemoDigitalAdapter extends DigitalAdapter<Void> {
public DemoDigitalAdapter(String id) {
super(id);
}
/**
* Callback to notify the adapter on its correct startup
*/
@Override
public void onAdapterStart() {}
/**
* Callback to notify the adapter that has been stopped
*/
@Override
public void onAdapterStop() {}
/**
* DT Life Cycle notification that the DT is correctly on Sync
* @param digitalTwinState
*/
@Override
public void onDigitalTwinSync(DigitalTwinState digitalTwinState) {}
/**
* DT Life Cycle notification that the DT is currently Not Sync
* @param digitalTwinState
*/
@Override
public void onDigitalTwinUnSync(DigitalTwinState digitalTwinState) {}
/**
* DT Life Cycle notification that the DT has been created
*/
@Override
public void onDigitalTwinCreate() {}
/**
* DT Life Cycle Notification that the DT has correctly Started
*/
@Override
public void onDigitalTwinStart() {}
/**
* DT Life Cycle Notification that the DT has been stopped
*/
@Override
public void onDigitalTwinStop() {}
/**
* DT Life Cycle Notification that the DT has destroyed
*/
@Override
public void onDigitalTwinDestroy() {}
/**
* Callback method allowing the Digital Adapter to receive the updated Digital Twin State together with
* the previous state and the list of applied changes
*
* @param newDigitalTwinState The new Digital Twin State computed by the Shadowing Function
* @param previousDigitalTwinState The previous Digital Twin State
* @param digitalTwinStateChangeList The list of applied changes to compute the new Digital Twin State
*/
@Override
protected void onStateUpdate(DigitalTwinState newDigitalTwinState, DigitalTwinState previousDigitalTwinState, ArrayList<DigitalTwinStateChange> digitalTwinStateChangeList) {}
/**
* Callback method to receive a new computed Event Notification (associated to event declared in the DT State)
*
* @param digitalTwinStateEventNotification The generated Notification associated to a DT Event
*/
@Override
protected void onEventNotificationReceived(DigitalTwinStateEventNotification<?> digitalTwinStateEventNotification) {}
}
By default, a Digital Adapter observes all the variation on the DT’s State in terms of Properties, Relationships, Actions and Events. As previously mentioned the observation of DT’s State Properties allows to receive also properties variation on the method since a property is natively composed by its description (e.g., type) and its current value. On the opposite the observation on DT’s State Action, Relationships and Events allow ONLY to receive callbacks when a new entity is added or an update is occurred without receiving updates on values variation.
The only thing that we should add in the onDigitalTwinSync(IDigitalTwinState currentDigitalTwinState)
callback is the direct observation for Events.
Following this approach we can change our Digital Adapter in the following methods:
In onDigitalTwinSync
we observe in this first simple implementation only the incoming values for declared Events in the DT’State.
As previously mentioned the observation of any variation of the State structure together with Properties Values are by default observed by any Digital Adapter.
In this method we use the internal variable digitalTwinState
to access the DT’s state and find available Events declaration that we would like to observe.
public void onDigitalTwinSync(IDigitalTwinState currentDigitalTwinState) {
try {
//Retrieve the list of available events and observe all variations
digitalTwinState.getEventList()
.map(eventList -> eventList.stream()
.map(DigitalTwinStateEvent::getKey)
.collect(Collectors.toList()))
.ifPresent(eventKeys -> {
try {
observeDigitalTwinEventsNotifications(eventKeys);
} catch (EventBusException e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Developers extending the DigitalAdapter
class should implement the onStateUpdate
method to define custom logic that
needs to be executed whenever the state of the Digital Twin is updated. This could include tasks such as processing state changes, updating internal variables, triggering specific actions, or notifying other components about the state update.
Here’s an example of how the method might be implemented in a concrete subclass of DigitalAdapter
:
@Override
protected void onStateUpdate(DigitalTwinState newDigitalTwinState,
DigitalTwinState previousDigitalTwinState,
ArrayList<DigitalTwinStateChange> digitalTwinStateChangeList) {
// In newDigitalTwinState we have the new DT State
System.out.println("New DT State is: " + newDigitalTwinState);
// The previous DT State is available through the variable previousDigitalTwinState
System.out.println("Previous DT State is: " + previousDigitalTwinState);
// We can also check each DT's state change potentially differentiating the behaviour for each change
if (digitalTwinStateChangeList != null && !digitalTwinStateChangeList.isEmpty()) {
// Iterate through each state change in the list
for (DigitalTwinStateChange stateChange : digitalTwinStateChangeList) {
// Get information from the state change
DigitalTwinStateChange.Operation operation = stateChange.getOperation();
DigitalTwinStateChange.ResourceType resourceType = stateChange.getResourceType();
DigitalTwinStateResource resource = stateChange.getResource();
// Perform different actions based on the type of operation
switch (operation) {
case OPERATION_UPDATE:
// Handle an update operation
System.out.println("Update operation on " + resourceType + ": " + resource);
break;
case OPERATION_UPDATE_VALUE:
// Handle an update value operation
System.out.println("Update value operation on " + resourceType + ": " + resource);
break;
case OPERATION_ADD:
// Handle an add operation
System.out.println("Add operation on " + resourceType + ": " + resource);
break;
case OPERATION_REMOVE:
// Handle a remove operation
System.out.println("Remove operation on " + resourceType + ": " + resource);
break;
default:
// Handle unknown operation (optional)
System.out.println("Unknown operation on " + resourceType + ": " + resource);
break;
}
}
} else {
// No state changes
System.out.println("No state changes detected.");
}
}
In this example, the method iterates over the list of state changes, extracts information about each change, and performs custom actions based on the changes. Developers can adapt this method to suit the specific requirements of their Digital Twin application.
Both Physical Adapters and Digital Adapters can be defined natively with a custom configuration provided by the developer as illustrated in the dedicated Section: Configurable Physical & Digital Adapters.