-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add UnknownDevice as the default deserialization strategy for unspeci…
…fied device subtypes.
- Loading branch information
1 parent
bfac19c
commit 2a9c1ed
Showing
5 changed files
with
219 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
...c/main/java/de/dvdgeisler/iot/dirigera/client/api/model/device/unknown/UnknownDevice.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package de.dvdgeisler.iot.dirigera.client.api.model.device.unknown; | ||
|
||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.*; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
/** | ||
* The {@link UnknownDevice} represents a minimal subtype of a device. An {@link UnknownDevice} is provided as the | ||
* default deserialization strategy in case Jackson reads a json blob whose subtype is not derivable by its | ||
* {@link Device#deviceType} entry. A corresponding record is created via the {@link UnknownDeviceDeserializer} in the | ||
* {@link UnknownDeviceCollector}. | ||
*/ | ||
@JsonDeserialize(using = UnknownDeviceDeserializer.class) | ||
public class UnknownDevice extends Device< | ||
DeviceAttributes<DeviceStateAttributes>, | ||
DeviceConfigurationAttributes> { | ||
|
||
public UnknownDevice( | ||
final String id, | ||
final DeviceCategory type, | ||
final DeviceType deviceType, | ||
final LocalDateTime createdAt, | ||
final Boolean isReachable, | ||
final LocalDateTime lastSeen, | ||
final DeviceAttributes<DeviceStateAttributes> attributes, | ||
final DeviceCapabilities capabilities, | ||
final List<String> remoteLinks, | ||
final DeviceConfigurationAttributes deviceConfigurationAttributes) { | ||
super(id, type, deviceType, createdAt, isReachable, lastSeen, attributes, capabilities, remoteLinks, deviceConfigurationAttributes); | ||
} | ||
|
||
public UnknownDevice() { | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
...va/de/dvdgeisler/iot/dirigera/client/api/model/device/unknown/UnknownDeviceCollector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package de.dvdgeisler.iot.dirigera.client.api.model.device.unknown; | ||
|
||
import com.fasterxml.jackson.databind.JsonNode; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.HashSet; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
/** | ||
* Collects records of deserialized devices for which no specialized deserialization strategy is defined. If a device | ||
* class is recorded as unknown for the first time, a corresponding warning is logged, including additional information | ||
* about it's JSON format. | ||
*/ | ||
public class UnknownDeviceCollector { | ||
private final static Logger log = LoggerFactory.getLogger(UnknownDeviceCollector.class); | ||
|
||
public static final UnknownDeviceCollector instance = new UnknownDeviceCollector(); | ||
|
||
public static class UnknownDeviceEntry { | ||
public final UnknownDevice device; | ||
public final JsonNode jsonNode; | ||
|
||
public UnknownDeviceEntry(final UnknownDevice device, final JsonNode jsonNode) { | ||
this.device = device; | ||
this.jsonNode = jsonNode; | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object o) { | ||
final UnknownDeviceEntry that; | ||
|
||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
that = (UnknownDeviceEntry) o; | ||
return Objects.equals(getDeviceCategory(this.device), getDeviceCategory(that.device)) && | ||
Objects.equals(getDeviceType(this.device), getDeviceType(that.device)) && | ||
Objects.equals(getDeviceManufacturer(this.device), getDeviceManufacturer(that.device)) && | ||
Objects.equals(getDeviceModel(this.device), getDeviceModel(that.device)) && | ||
Objects.equals(getDeviceCustomName(this.device), getDeviceCustomName(that.device)); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash( | ||
getDeviceCategory(this.device), | ||
getDeviceType(this.device), | ||
getDeviceManufacturer(this.device), | ||
getDeviceModel(this.device), | ||
getDeviceCustomName(this.device)); | ||
} | ||
} | ||
|
||
private final Set<UnknownDeviceEntry> entries; | ||
|
||
private UnknownDeviceCollector() { | ||
this.entries = new HashSet<>(); | ||
} | ||
|
||
private boolean add(final UnknownDeviceEntry unknownDeviceEntry) { | ||
if (this.entries.add(unknownDeviceEntry)) { | ||
log.warn(""" | ||
Unknown device found: | ||
type={}, category={}, | ||
manufacturer={}, model={}, | ||
customName={}, id={} | ||
Help us to support additional devices and create an issue on | ||
{} with the following content: | ||
{} | ||
""", | ||
getDeviceCategory(unknownDeviceEntry.device), | ||
getDeviceType(unknownDeviceEntry.device), | ||
getDeviceManufacturer(unknownDeviceEntry.device), | ||
getDeviceModel(unknownDeviceEntry.device), | ||
getDeviceCustomName(unknownDeviceEntry.device), | ||
getDeviceId(unknownDeviceEntry.device), | ||
"https://github.com/dvdgeisler/DirigeraClient", | ||
unknownDeviceEntry.jsonNode); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
public boolean add(final UnknownDevice unknownDevice, final JsonNode jsonNode) { | ||
return this.add(new UnknownDeviceEntry(unknownDevice, jsonNode)); | ||
} | ||
|
||
private static DeviceCategory getDeviceCategory(final UnknownDevice device) { | ||
return Optional.ofNullable(device).map(d -> d.type).orElse(null); | ||
} | ||
|
||
private static DeviceType getDeviceType(final UnknownDevice device) { | ||
return Optional.ofNullable(device).map(d -> d.deviceType).orElse(null); | ||
} | ||
|
||
private static String getDeviceManufacturer(final UnknownDevice device) { | ||
return Optional.ofNullable(device).map(d -> d.attributes).map(a -> a.manufacturer).orElse(null); | ||
} | ||
|
||
private static String getDeviceModel(final UnknownDevice device) { | ||
return Optional.ofNullable(device).map(d -> d.attributes).map(a -> a.model).orElse(null); | ||
} | ||
|
||
private static String getDeviceCustomName(final UnknownDevice device) { | ||
return Optional.ofNullable(device).map(d -> d.attributes).map(a -> a.state).map(s -> s.customName).orElse(null); | ||
} | ||
|
||
private static String getDeviceId(final UnknownDevice device) { | ||
return Optional.ofNullable(device).map(d -> d.id).orElse(null); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...de/dvdgeisler/iot/dirigera/client/api/model/device/unknown/UnknownDeviceDeserializer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package de.dvdgeisler.iot.dirigera.client.api.model.device.unknown; | ||
|
||
import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
import com.fasterxml.jackson.core.JsonParser; | ||
import com.fasterxml.jackson.databind.DeserializationContext; | ||
import com.fasterxml.jackson.databind.JsonDeserializer; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | ||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* Deserializes an unknown device into an {@link UnknownDevice} instance. Furthermore, a corresponding record is created | ||
* in the {@link UnknownDeviceCollector} for analytical purposes. | ||
*/ | ||
public class UnknownDeviceDeserializer extends StdDeserializer<UnknownDevice> { | ||
|
||
/** | ||
* Extends an {@link UnknownDevice} to overwrite its Jackson deserialization strategy | ||
*/ | ||
@JsonDeserialize(using = JsonDeserializer.None.class) | ||
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) | ||
private static class UnknownDeviceWrapper extends UnknownDevice { | ||
} | ||
|
||
protected UnknownDeviceDeserializer() { | ||
super(UnknownDevice.class); | ||
} | ||
|
||
@Override | ||
public UnknownDevice deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException { | ||
final JsonNode jsonNode; | ||
final UnknownDeviceWrapper defaultDevice; | ||
|
||
jsonNode = ctxt.readTree(p); | ||
defaultDevice = ctxt.readTreeAsValue(jsonNode, UnknownDeviceWrapper.class); | ||
UnknownDeviceCollector.instance.add(defaultDevice, jsonNode); | ||
|
||
return defaultDevice; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...st/java/de/dvdgeisler/iot/dirigera/client/api/model/device/unknown/UnknownDeviceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package de.dvdgeisler.iot.dirigera.client.api.model.device.unknown; | ||
|
||
import de.dvdgeisler.iot.dirigera.client.api.model.device.Device; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceTest; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
class UnknownDeviceTest extends DeviceTest { | ||
final static String JSON = "{\"id\" : \"123\"}"; | ||
|
||
public UnknownDeviceTest() { | ||
super(JSON); | ||
} | ||
|
||
@Override | ||
public void validateDeserialize(final Device<?,?> device) { | ||
assertTrue(device instanceof UnknownDevice); | ||
} | ||
} |