openhab-docs/developers/utils/tools.md

117 lines
5.4 KiB
Markdown
Raw Normal View History

Rewrite developer section (#942) * Rewrite developer section * More work on module types * More module-type stuff * Adapt vuepress files * Write binding doc * Add TODOs for missing topics * Add all missing topics from ESH. * Tests * Audio extensions * Utilities * i18n * Event-bus * Small fixes * Command Description * Add some tocs * Add concept drawing to binding dev. * Update developers/osgi/configadmin.md Co-Authored-By: davidgraeff <david.graeff@web.de> * Update administration/logging.md Co-Authored-By: davidgraeff <david.graeff@web.de> * Update developers/bindings/thing-xml.md Co-Authored-By: davidgraeff <david.graeff@web.de> * Convert HTML tables to Markdown Signed-off-by: Hakan Tandogan <hakan@tandogan.com> * Resolved one line per sentence review parts. Signed-off-by: Jerome Luckenbach <github@luckenba.ch> * Update developers/index.md * Update developers/buildsystem.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Add persistence placeholder. Address review comments * fix persistence subdirectory Signed-off-by: David Graeff <david.graeff@web.de> * Update developers/audio/index.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/guidelines.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/contributing.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/buildsystem.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/guidelines.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/index.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/index.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/osgi/osgids.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/transformations/index.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Update developers/ioservices/index.md Co-Authored-By: davidgraeff <davgraeff@gmail.com> * Remove extensionservices (for now ;) Signed-off-by: David Graeff <david.graeff@web.de> * Fix typos Signed-off-by: David Graeff <david.graeff@web.de> * Added example code for 'DynamicCommandDescriptionProvider' and 'DynamicCommandDescriptionProvider' Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de> * Added example code for 'ThingHandlerFactory' Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de> * Applied review comments Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
2019-05-02 18:52:37 +00:00
---
layout: developersguide
title: Framework Tools
---
# Framework Tools
Find a few framework utilities listed in this chapter.
# Unique Instance ID
When communicating with external systems, it is often desirable to have a unique identifier.
The `org.eclipse.smarthome.core.id` bundle is a mean to generate such an id, which is automatically persisted.
The persistence is done in the configured `userdata` directory as a file called `uuid`.
The id is provided through a static method and can be retrieved through
```java
String uuid = InstanceUUID.get();
```
# Network Address Service
The `NetworkAddressService` is an OSGi service that can be used like any other OSGi service by adding a service reference to it.
Its OSGi service name is `org.eclipse.smarthome.network`.
A user can configure his default network address via Paper UI under `Configuration -> System -> Network Settings`.
One can obtain the configured address via the `getPrimaryIpv4HostAddress()` method on the service.
This service is useful for example in the `ThingHandlerFactory` or an `AudioSink` where one needs a specific IP address of the host system to provide something like a `callback` URL.
Some static methods like `getAllBroadcastAddresses()` for retrieving all interface broadcast addresses or `getInterfaceAddresses()` for retrieving all assigned interface addresses might be usefull as well for discovery services.
## Network Address Change Listener
The `NetworkAddressChangeListener` is a consumer type OSGi service interface.
If listeners want to be notified about network interface address changes, they can implement `NetworkAddressChangeListener` and register as an OSGi service.
Please be aware that not all network interface changes are notified to the listeners, only "useful" network interfaces :--
When a network interface status changes from "up" to "down", it is considered as "removed".
When a "loopback" or "down" interface is added, the listeners are not notified.
# Caching
The framework provides some caching solutions for common scenarios.
A common usage case is in a `ThingHandler` to encapsulate one value of an internal state and attach an expire time on that value.
A cache action will be called to refresh the value if it is expired.
This is what `ExpiringCache` implements.
If `handleCommand(ChannelUID channelUID, Command command)` is called with the "RefreshType" command, you just return `cache.getValue()`.
It is a good practice to return as fast as possible from the `handleCommand(ChannelUID channelUID, Command command)` method to not block callers especially UIs.
Use this type of cache only, if your refresh action is a quick to compute, blocking operation.
If you deal with network calls, consider the asynchronously reloading cache implementation instead.
## Expiring and asynchronously reloading cache
If we refreshed a value of the internal state in a `ThingHandler` just recently, we can return it immediately via the usual `updateState(channel, state)` method in response to a "RefreshType" command.
If the state is too old, we need to fetch it first and this may involve network calls, interprocess operations or anything else that will would block for a considerable amout of time.
A common usage case of the `ExpiringCacheAsync` cache type is in a `ThingHandler` to encapsulate one value of an internal state and attach an expire time on that value.
A **handleCommand** implementation with the interesting *RefreshType* could look like this:
```java
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case CHANNEL_1:
cache1.getValue(updater).thenAccept(value -> updateState(CHANNEL_1, value));
break;
...
}
}
}
```
The interesting part is the `updater`.
If the value is not yet expired, the returned CompletableFuture will complete immediately and the given code is executed.
If the value is expired, the updater will be used to request a refreshed value.
An updater can be any class or lambda that implements the funtional interface of `Supplier<CompletableFuture<VALUE_TYPE>>`.
In the following example the method `CompletableFuture<VALUE_TYPE> get()` is accordingly implemented.
The example assumes that we deal
with a still very common callback based device refreshing method `doSuperImportantAsyncStuffHereToGetRefreshedValue(listener)`.
The listener is the class
itself, which implements `DeviceStateUpdateListener`.
We will be called back with a refreshed device state in `asyncCallbackFromDeviceStateRefresh`
and mark the Future as *complete*.
```java
class FetchValueFromDevice implements Supplier<CompletableFuture<double>>, DeviceStateUpdateListener {
CompletableFuture<double> c;
@Override
CompletableFuture<double> get() {
if (c != null) {
c = new CompletableFuture<double>();
doSuperImportantAsyncStuffHereToGetRefreshedValue( (DeviceStateUpdateListener)this );
}
return c;
}
// Here you process the callback from your device refresh method
@Override
void asyncCallbackFromDeviceStateRefresh(double newValue) {
// Notify the future that we have something
if (c != null) {
c.complete(newValue);
c = null;
}
}
}
```
If you deal with a newer implementation with a CompletableFuture support, it is even easier.
You would just return your CompletableFuture.