From 645bbac2967c528182a46f2122d09e1a90dab146 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Thu, 15 Aug 2019 22:20:09 +0200 Subject: [PATCH] [systeminfo] Update dependencies and add null annotations (#5929) * [systeminfo] Update dependencies and add null annotations * Update oshi to 4.0.0 * Update jna to 5.4.0 * Add null annotations The cpu#load channel is removed because its data is no longer provided by oshi. The load1, load5 and load15 channels can be used instead. On the Oracle JVM this information can also be obtained using com.sun.management.OperatingSystemMXBean.getSystemCpuLoad() See also: * https://github.com/oshi/oshi/blob/master/UPGRADING.md * https://github.com/oshi/oshi/blob/master/CHANGELOG.md#400-8102019 Fixes #5921 Signed-off-by: Wouter Born Signed-off-by: Tim Roberts --- .../org.openhab.binding.systeminfo/README.md | 7 +- .../org.openhab.binding.systeminfo/pom.xml | 6 +- .../src/main/feature/feature.xml | 6 +- .../internal/SysteminfoHandlerFactory.java | 8 +- .../discovery/SysteminfoDiscoveryService.java | 3 + .../internal/handler/SysteminfoHandler.java | 119 +++++++++--------- .../model/DeviceNotFoundException.java | 4 + .../internal/model/OSHISysteminfo.java | 108 ++++++++-------- .../internal/model/SysteminfoInterface.java | 53 ++++---- .../main/resources/ESH-INF/thing/channels.xml | 9 -- .../itest.bndrun | 8 +- .../pom.xml | 6 +- .../systeminfo/test/SysteminfoOSGiTest.java | 16 +-- 13 files changed, 169 insertions(+), 184 deletions(-) diff --git a/bundles/org.openhab.binding.systeminfo/README.md b/bundles/org.openhab.binding.systeminfo/README.md index 74be19c20fb06..a5ad9ce46f898 100644 --- a/bundles/org.openhab.binding.systeminfo/README.md +++ b/bundles/org.openhab.binding.systeminfo/README.md @@ -3,7 +3,7 @@ System information Binding provides operating system and hardware information including: - Operating system name, version and manufacturer; -- CPU average recent load and load for last 1, 5, 15 minutes, name, description, number of physical and logical cores, running threads number, system uptime; +- CPU average load for last 1, 5, 15 minutes, name, description, number of physical and logical cores, running threads number, system uptime; - Free, total and available memory; - Free, total and available swap memory; - Hard drive name, model and serial number; @@ -81,7 +81,7 @@ In the list below, you can find, how are channel group and channels id`s related * **group** `battery` (deviceIndex) * **channel** `name, remainingCapacity, remainingTime` * **group** `cpu` - * **channel** `name, description, load, load1, load5, load15, uptime` + * **channel** `name, description, load1, load5, load15, uptime` * **group** `sensors` * **channel** `cpuTemp, cpuVoltage, fanSpeed` * **group** `network` (deviceIndex) @@ -108,7 +108,6 @@ The binding introduces the following channels: | Channel ID | Channel Description | Supported item type | Default priority | Advanced | |--------------------|------------------------------------------------------------------|---------------------|------------------|----------| -| load | Recent load in percents | Number | High | False | | load1 | Load for the last 1 minute | Number | Medium | True | | load5 | Load for the last 5 minutes | Number | Medium | True | | load15 | Load for the last 15 minutes | Number | Medium | True | @@ -207,7 +206,6 @@ Number Network_PacketsReceived "Packets received" { chann /* CPU information*/ String CPU_Name "Name" { channel="systeminfo:computer:work:cpu#name" } String CPU_Description "Description" { channel="systeminfo:computer:work:cpu#description" } -Number CPU_Load "Load" { channel="systeminfo:computer:work:cpu#load"} Number CPU_Load1 "Load (1 min)" { channel="systeminfo:computer:work:cpu#load1" } Number CPU_Load5 "Load (5 min)" { channel="systeminfo:computer:work:cpu#load5" } Number CPU_Load15 "Load (15 min)" { channel="systeminfo:computer:work:cpu#load15" } @@ -281,7 +279,6 @@ Text label="Systeminfo" { Frame label="CPU Information" { Default item=CPU_Name Default item=CPU_Description - Default item=CPU_Load Default item=CPU_Load1 Default item=CPU_Load5 Default item=CPU_Load15 diff --git a/bundles/org.openhab.binding.systeminfo/pom.xml b/bundles/org.openhab.binding.systeminfo/pom.xml index bf2408e79d0a4..588eb7bd2bb96 100644 --- a/bundles/org.openhab.binding.systeminfo/pom.xml +++ b/bundles/org.openhab.binding.systeminfo/pom.xml @@ -17,19 +17,19 @@ net.java.dev.jna jna-platform - 5.3.0 + 5.4.0 provided net.java.dev.jna jna - 5.3.0 + 5.4.0 provided com.github.oshi oshi-core - 3.13.0 + 4.0.0 provided diff --git a/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml b/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml index ecd320c9436d3..f16e2e4982bc2 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml @@ -4,9 +4,9 @@ openhab-runtime-base - mvn:net.java.dev.jna/jna/5.3.0 - mvn:net.java.dev.jna/jna-platform/5.3.0 - mvn:com.github.oshi/oshi-core/3.13.0 + mvn:net.java.dev.jna/jna/5.4.0 + mvn:net.java.dev.jna/jna-platform/5.4.0 + mvn:com.github.oshi/oshi-core/4.0.0 mvn:org.openhab.addons.bundles/org.openhab.binding.systeminfo/${project.version} diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/SysteminfoHandlerFactory.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/SysteminfoHandlerFactory.java index 7a74cd5b410b0..caae1556a11aa 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/SysteminfoHandlerFactory.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/SysteminfoHandlerFactory.java @@ -17,6 +17,8 @@ import java.util.Collections; import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; @@ -33,13 +35,15 @@ * * @author Svilen Valkanov - Initial contribution * @author Lyubomir Papazov - Pass systeminfo service to the SysteminfoHandler constructor + * @author Wouter Born - Add null annotations */ +@NonNullByDefault @Component(service = ThingHandlerFactory.class, configurationPid = "binding.systeminfo") public class SysteminfoHandlerFactory extends BaseThingHandlerFactory { private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_COMPUTER); - private SysteminfoInterface systeminfo; + private @NonNullByDefault({}) SysteminfoInterface systeminfo; @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -47,7 +51,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { } @Override - protected ThingHandler createHandler(Thing thing) { + protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (thingTypeUID.equals(THING_TYPE_COMPUTER)) { diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/discovery/SysteminfoDiscoveryService.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/discovery/SysteminfoDiscoveryService.java index f847b4d1699d6..1707e9eb41ac6 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/discovery/SysteminfoDiscoveryService.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/discovery/SysteminfoDiscoveryService.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; @@ -35,7 +36,9 @@ * {@link #DEFAULT_THING_LABEL}. The discovered Thing will have id - the hostname or {@link #DEFAULT_THING_ID}' * * @author Svilen Valkanov - Initial contribution + * @author Wouter Born - Add null annotations */ +@NonNullByDefault @Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.systeminfo") public class SysteminfoDiscoveryService extends AbstractDiscoveryService { public static final String DEFAULT_THING_ID = "unknown"; diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java index 7a3d83d03add5..71fdfadf0e6b6 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java @@ -23,7 +23,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.thing.Channel; import org.eclipse.smarthome.core.thing.ChannelUID; @@ -46,39 +47,40 @@ * * @author Svilen Valkanov - Initial contribution * @author Lyubomir Papzov - Separate the creation of the systeminfo object and its initialization + * @author Wouter Born - Add null annotations */ - +@NonNullByDefault public class SysteminfoHandler extends BaseThingHandler { /** * Refresh interval for {@link #highPriorityChannels} in seconds. */ - private BigDecimal refreshIntervalHighPriority; + private @NonNullByDefault({}) BigDecimal refreshIntervalHighPriority; /** * Refresh interval for {@link #mediumPriorityChannels} in seconds. */ - private BigDecimal refreshIntervalMediumPriority; + private @NonNullByDefault({}) BigDecimal refreshIntervalMediumPriority; /** * Channels with priority configuration parameter set to High. They usually need frequent update of the state like * CPU load, or information about the free and used memory. * They are updated periodically at {@link #refreshIntervalHighPriority}. */ - private Set highPriorityChannels = new HashSet<>(); + private final Set highPriorityChannels = new HashSet<>(); /** * Channels with priority configuration parameter set to Medium. These channels usually need update of the * state not so oft like battery capacity, storage used and etc. * They are updated periodically at {@link #refreshIntervalMediumPriority}. */ - private Set mediumPriorityChannels = new HashSet<>(); + private final Set mediumPriorityChannels = new HashSet<>(); /** * Channels with priority configuration parameter set to Low. They represent static information or information * that is updated rare- e.g. CPU name, storage name and etc. * They are updated only at {@link #initialize()}. */ - private Set lowPriorityChannels = new HashSet<>(); + private final Set lowPriorityChannels = new HashSet<>(); /** * Wait time for the creation of Item-Channel links in seconds. This delay is needed, because the Item-Channel @@ -88,12 +90,12 @@ public class SysteminfoHandler extends BaseThingHandler { private SysteminfoInterface systeminfo; - ScheduledFuture highPriorityTasks; - ScheduledFuture mediumPriorityTasks; + private @Nullable ScheduledFuture highPriorityTasks; + private @Nullable ScheduledFuture mediumPriorityTasks; private Logger logger = LoggerFactory.getLogger(SysteminfoHandler.class); - public SysteminfoHandler(@NonNull Thing thing, SysteminfoInterface systeminfo) { + public SysteminfoHandler(Thing thing, @Nullable SysteminfoInterface systeminfo) { super(thing); if (systeminfo != null) { this.systeminfo = systeminfo; @@ -238,13 +240,11 @@ private void scheduleUpdates() { } private void publishData(Set channels) { - if (channels != null) { - Iterator iter = channels.iterator(); - while (iter.hasNext()) { - ChannelUID channeUID = iter.next(); - if (isLinked(channeUID.getId())) { - publishDataForChannel(channeUID); - } + Iterator iter = channels.iterator(); + while (iter.hasNext()) { + ChannelUID channeUID = iter.next(); + if (isLinked(channeUID.getId())) { + publishDataForChannel(channeUID); } } } @@ -252,12 +252,7 @@ private void publishData(Set channels) { private void publishDataForChannel(ChannelUID channelUID) { State state = getInfoForChannel(channelUID); String channelID = channelUID.getId(); - if (state != null) { - updateState(channelID, state); - } else { - logger.warn("Channel with ID {} cannot be updated! No information available for the selected device.", - channelID); - } + updateState(channelID, state); } public Set getHighPriorityChannels() { @@ -282,6 +277,7 @@ public Set getLowPriorityChannels() { */ private State getInfoForChannel(ChannelUID channelUID) { State state = null; + String channelID = channelUID.getId(); String channelIDWithoutGroup = channelUID.getIdWithoutGroup(); String channelGroupID = channelUID.getGroupId(); @@ -291,7 +287,9 @@ private State getInfoForChannel(ChannelUID channelUID) { // The channelGroup may contain deviceIndex. It must be deleted from the channelID, because otherwise the // switch will not find the correct method below. // All digits are deleted from the ID - channelID = channelGroupID.replaceAll("\\d+", "") + "#" + channelIDWithoutGroup; + if (channelGroupID != null) { + channelID = channelGroupID.replaceAll("\\d+", "") + "#" + channelIDWithoutGroup; + } try { switch (channelID) { @@ -316,9 +314,6 @@ private State getInfoForChannel(ChannelUID channelUID) { case CHANNEL_SENSORS_FAN_SPEED: state = systeminfo.getSensorsFanSpeed(deviceIndex); break; - case CHANNEL_CPU_LOAD: - state = systeminfo.getCpuLoad(); - break; case CHANNEL_CPU_LOAD_1: state = systeminfo.getCpuLoad1(); break; @@ -465,22 +460,26 @@ private State getInfoForChannel(ChannelUID channelUID) { * @return natural number (number >=0) */ private int getDeviceIndex(ChannelUID channelUID) { - int deviceIndex = 0; - if (channelUID.getGroupId().contains(CHANNEL_GROUP_PROCESS)) { + String channelGroupID = channelUID.getGroupId(); + if (channelGroupID == null) { + return 0; + } + + if (channelGroupID.contains(CHANNEL_GROUP_PROCESS)) { // Only in this case the deviceIndex is part of the channel configuration - PID (Process Identifier) int pid = getPID(channelUID); - deviceIndex = pid; logger.debug("Channel with UID {} tracks process with PID: {}", channelUID, pid); - } else { - String channelGroupID = channelUID.getGroupId(); - char lastChar = channelGroupID.charAt(channelGroupID.length() - 1); - if (Character.isDigit(lastChar)) { - // All non-digits are deleted from the ID - String deviceIndexPart = channelGroupID.replaceAll("\\D+", ""); - deviceIndex = Integer.parseInt(deviceIndexPart); - } + return pid; + } + + char lastChar = channelGroupID.charAt(channelGroupID.length() - 1); + if (Character.isDigit(lastChar)) { + // All non-digits are deleted from the ID + String deviceIndexPart = channelGroupID.replaceAll("\\D+", ""); + return Integer.parseInt(deviceIndexPart); } - return deviceIndex; + + return 0; } /** @@ -492,14 +491,18 @@ private int getDeviceIndex(ChannelUID channelUID) { private int getPID(ChannelUID channelUID) { int pid = 0; try { - Configuration channelProperties = this.thing.getChannel(channelUID.getId()).getConfiguration(); - BigDecimal pidValue = (BigDecimal) channelProperties.get(PID_PARAM); - if (pidValue == null || pidValue.intValue() < 0) { - throw new IllegalArgumentException("Invalid value for Process Identifier."); + Channel channel = this.thing.getChannel(channelUID.getId()); + if (channel != null) { + Configuration channelProperties = channel.getConfiguration(); + BigDecimal pidValue = (BigDecimal) channelProperties.get(PID_PARAM); + if (pidValue == null || pidValue.intValue() < 0) { + throw new IllegalArgumentException("Invalid value for Process Identifier."); + } else { + pid = pidValue.intValue(); + } } else { - pid = pidValue.intValue(); + logger.debug("Channel does not exist ! Fall back to default value."); } - } catch (ClassCastException e) { logger.debug("Channel configuration cannot be read ! Fall back to default value.", e); } catch (IllegalArgumentException e) { @@ -523,17 +526,14 @@ public void handleCommand(ChannelUID channelUID, Command command) { } private boolean isConfigurationKeyChanged(Configuration currentConfig, Configuration newConfig, String key) { - if (currentConfig != null && newConfig != null) { - Object currentValue = currentConfig.get(key); - Object newValue = newConfig.get(key); - - if (currentValue == null) { - return (newValue != null); - } + Object currentValue = currentConfig.get(key); + Object newValue = newConfig.get(key); - return !currentValue.equals(newValue); + if (currentValue == null) { + return (newValue != null); } - return true; + + return !currentValue.equals(newValue); } @Override @@ -586,13 +586,16 @@ private void handleChannelConfigurationChange(Channel channel, Configuration new } private void stopScheduledUpdates() { - if (highPriorityTasks != null) { + ScheduledFuture localHighPriorityTasks = highPriorityTasks; + if (localHighPriorityTasks != null) { logger.debug("High prioriy tasks will not be run anymore !"); - highPriorityTasks.cancel(true); + localHighPriorityTasks.cancel(true); } - if (mediumPriorityTasks != null) { + + ScheduledFuture localMediumPriorityTasks = mediumPriorityTasks; + if (localMediumPriorityTasks != null) { logger.debug("Medium prioriy tasks will not be run anymore !"); - mediumPriorityTasks.cancel(true); + localMediumPriorityTasks.cancel(true); } } diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/DeviceNotFoundException.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/DeviceNotFoundException.java index 036cb6992b6b0..ddd6e74bf2c5c 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/DeviceNotFoundException.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/DeviceNotFoundException.java @@ -14,12 +14,16 @@ import java.io.IOException; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * {@link DeviceNotFoundException} is used to indicate that device can not be found on this hardware configuration, most * probably because the device is not installed. * * @author Svilen Valkanov - Initial contribution + * @author Wouter Born - Add null annotations */ +@NonNullByDefault public class DeviceNotFoundException extends IOException { private static final long serialVersionUID = -707507777792259512L; diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java index 7df2c97163211..a8c018210d346 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java @@ -15,6 +15,8 @@ import java.math.BigDecimal; import org.apache.commons.lang.ArrayUtils; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.StringType; import org.osgi.service.component.annotations.Component; @@ -45,29 +47,31 @@ * initializeSysteminfo method * @author Christoph Weitkamp - Update to OSHI 3.13.0 - Replaced deprecated method * CentralProcessor#getSystemSerialNumber() + * @author Wouter Born - Update to OSHI 4.0.0 and add null annotations * * @see OSHI github repository */ +@NonNullByDefault @Component(service = SysteminfoInterface.class) public class OSHISysteminfo implements SysteminfoInterface { - HardwareAbstractionLayer hal; + private final Logger logger = LoggerFactory.getLogger(OSHISysteminfo.class); - private Logger logger = LoggerFactory.getLogger(OSHISysteminfo.class); + private @NonNullByDefault({}) HardwareAbstractionLayer hal; // Dynamic objects (may be queried repeatedly) - private GlobalMemory memory; - private CentralProcessor cpu; - private Sensors sensors; + private @NonNullByDefault({}) GlobalMemory memory; + private @NonNullByDefault({}) CentralProcessor cpu; + private @NonNullByDefault({}) Sensors sensors; // Static objects, should be recreated on each request - private ComputerSystem computerSystem; - private OperatingSystem operatingSystem; - private NetworkIF[] networks; - private Display[] displays; - private OSFileStore[] fileStores; - private PowerSource[] powerSources; - private HWDiskStore[] drives; + private @NonNullByDefault({}) ComputerSystem computerSystem; + private @NonNullByDefault({}) OperatingSystem operatingSystem; + private @NonNullByDefault({}) NetworkIF[] networks; + private @NonNullByDefault({}) Display[] displays; + private @NonNullByDefault({}) OSFileStore[] fileStores; + private @NonNullByDefault({}) PowerSource[] powerSources; + private @NonNullByDefault({}) HWDiskStore[] drives; public static final int PRECISION_AFTER_DECIMAL_SIGN = 1; @@ -103,9 +107,8 @@ public void initializeSysteminfo() { drives = hal.getDiskStores(); } - @SuppressWarnings("null") - private Object getDevice(Object[] devices, int index) throws DeviceNotFoundException { - if ((devices != null) && (devices.length <= index)) { + private Object getDevice(Object @Nullable [] devices, int index) throws DeviceNotFoundException { + if ((devices == null) || (devices.length <= index)) { throw new DeviceNotFoundException("Device with index: " + index + " can not be found!"); } return devices[index]; @@ -170,13 +173,6 @@ public DecimalType getCpuPhysicalCores() { return new DecimalType(physicalProcessorCount); } - @Override - public DecimalType getCpuLoad() { - double processorLoad = cpu.getSystemCpuLoad(); - BigDecimal processorLoadPercent = getPercentsValue(processorLoad); - return new DecimalType(processorLoadPercent); - } - @Override public DecimalType getMemoryTotal() { long totalMemory = memory.getTotal(); @@ -236,7 +232,7 @@ public DecimalType getStorageUsed(int index) throws DeviceNotFoundException { } @Override - public DecimalType getStorageAvailablePercent(int deviceIndex) throws DeviceNotFoundException { + public @Nullable DecimalType getStorageAvailablePercent(int deviceIndex) throws DeviceNotFoundException { // In the current OSHI version a new query is required for the storage data values to be updated // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 fileStores = operatingSystem.getFileSystem().getFileStores(); @@ -253,7 +249,7 @@ public DecimalType getStorageAvailablePercent(int deviceIndex) throws DeviceNotF } @Override - public DecimalType getStorageUsedPercent(int deviceIndex) throws DeviceNotFoundException { + public @Nullable DecimalType getStorageUsedPercent(int deviceIndex) throws DeviceNotFoundException { // In the current OSHI version a new query is required for the storage data values to be updated // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 fileStores = operatingSystem.getFileSystem().getFileStores(); @@ -333,28 +329,28 @@ public StringType getDisplayInformation(int index) throws DeviceNotFoundExceptio } @Override - public DecimalType getSensorsCpuTemperature() { + public @Nullable DecimalType getSensorsCpuTemperature() { BigDecimal cpuTemp = new BigDecimal(sensors.getCpuTemperature()); cpuTemp = cpuTemp.setScale(PRECISION_AFTER_DECIMAL_SIGN, BigDecimal.ROUND_HALF_UP); return cpuTemp.signum() == 1 ? new DecimalType(cpuTemp) : null; } @Override - public DecimalType getSensorsCpuVoltage() { + public @Nullable DecimalType getSensorsCpuVoltage() { BigDecimal cpuVoltage = new BigDecimal(sensors.getCpuVoltage()); cpuVoltage = cpuVoltage.setScale(PRECISION_AFTER_DECIMAL_SIGN, BigDecimal.ROUND_HALF_UP); return cpuVoltage.signum() == 1 ? new DecimalType(cpuVoltage) : null; } @Override - public DecimalType getSensorsFanSpeed(int index) throws DeviceNotFoundException { + public @Nullable DecimalType getSensorsFanSpeed(int index) throws DeviceNotFoundException { int[] fanSpeeds = sensors.getFanSpeeds(); int speed = (int) getDevice(ArrayUtils.toObject(fanSpeeds), index); return speed > 0 ? new DecimalType(speed) : null; } @Override - public DecimalType getBatteryRemainingTime(int index) throws DeviceNotFoundException { + public @Nullable DecimalType getBatteryRemainingTime(int index) throws DeviceNotFoundException { // In the current OSHI version a new query is required for the battery data values to be updated // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 powerSources = hal.getPowerSources(); @@ -384,7 +380,7 @@ public StringType getBatteryName(int index) throws DeviceNotFoundException { } @Override - public DecimalType getMemoryAvailablePercent() { + public @Nullable DecimalType getMemoryAvailablePercent() { long availableMemory = memory.getAvailable(); long totalMemory = memory.getTotal(); if (totalMemory > 0) { @@ -397,7 +393,7 @@ public DecimalType getMemoryAvailablePercent() { } @Override - public DecimalType getMemoryUsedPercent() { + public @Nullable DecimalType getMemoryUsedPercent() { long availableMemory = memory.getAvailable(); long totalMemory = memory.getTotal(); long usedMemory = totalMemory - availableMemory; @@ -432,32 +428,32 @@ public StringType getDriveSerialNumber(int deviceIndex) throws DeviceNotFoundExc } @Override - public DecimalType getSwapTotal() { - long swapTotal = memory.getSwapTotal(); + public @Nullable DecimalType getSwapTotal() { + long swapTotal = memory.getVirtualMemory().getSwapTotal(); swapTotal = getSizeInMB(swapTotal); return swapTotal > 0 ? new DecimalType(swapTotal) : null; } @Override - public DecimalType getSwapAvailable() { - long swapTotal = memory.getSwapTotal(); - long swapUsed = memory.getSwapUsed(); + public @Nullable DecimalType getSwapAvailable() { + long swapTotal = memory.getVirtualMemory().getSwapTotal(); + long swapUsed = memory.getVirtualMemory().getSwapUsed(); long swapAvaialble = swapTotal - swapUsed; swapAvaialble = getSizeInMB(swapAvaialble); return swapAvaialble > 0 ? new DecimalType(swapAvaialble) : null; } @Override - public DecimalType getSwapUsed() { - long swapTotal = memory.getSwapUsed(); + public @Nullable DecimalType getSwapUsed() { + long swapTotal = memory.getVirtualMemory().getSwapUsed(); swapTotal = getSizeInMB(swapTotal); return swapTotal > 0 ? new DecimalType(swapTotal) : null; } @Override - public DecimalType getSwapAvailablePercent() { - long usedSwap = memory.getSwapUsed(); - long totalSwap = memory.getSwapTotal(); + public @Nullable DecimalType getSwapAvailablePercent() { + long usedSwap = memory.getVirtualMemory().getSwapUsed(); + long totalSwap = memory.getVirtualMemory().getSwapTotal(); long freeSwap = totalSwap - usedSwap; if (totalSwap > 0) { double freePercentDecimal = (double) freeSwap / (double) totalSwap; @@ -469,9 +465,9 @@ public DecimalType getSwapAvailablePercent() { } @Override - public DecimalType getSwapUsedPercent() { - long usedSwap = memory.getSwapUsed(); - long totalSwap = memory.getSwapTotal(); + public @Nullable DecimalType getSwapUsedPercent() { + long usedSwap = memory.getVirtualMemory().getSwapUsed(); + long totalSwap = memory.getVirtualMemory().getSwapTotal(); if (totalSwap > 0) { double usedPercentDecimal = (double) usedSwap / (double) totalSwap; BigDecimal usedPercent = getPercentsValue(usedPercentDecimal); @@ -503,7 +499,7 @@ private BigDecimal getTimeInMinutes(double timeInSeconds) { * This information is available only on Mac and Linux OS. */ @Override - public DecimalType getCpuLoad1() { + public @Nullable DecimalType getCpuLoad1() { BigDecimal avarageCpuLoad = getAvarageCpuLoad(1); return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad); } @@ -514,7 +510,7 @@ public DecimalType getCpuLoad1() { * This information is available only on Mac and Linux OS. */ @Override - public DecimalType getCpuLoad5() { + public @Nullable DecimalType getCpuLoad5() { BigDecimal avarageCpuLoad = getAvarageCpuLoad(5); return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad); } @@ -525,7 +521,7 @@ public DecimalType getCpuLoad5() { * This information is available only on Mac and Linux OS. */ @Override - public DecimalType getCpuLoad15() { + public @Nullable DecimalType getCpuLoad15() { BigDecimal avarageCpuLoad = getAvarageCpuLoad(15); return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad); } @@ -554,7 +550,7 @@ private BigDecimal getAvarageCpuLoad(int timeInMunutes) { @Override public DecimalType getCpuUptime() { - long seconds = cpu.getSystemUptime(); + long seconds = operatingSystem.getSystemUptime(); return new DecimalType(getTimeInMinutes(seconds)); } @@ -577,7 +573,7 @@ public DecimalType getNetworkPacketsReceived(int networkIndex) throws DeviceNotF // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 networks = hal.getNetworkIFs(); NetworkIF network = (NetworkIF) getDevice(networks, networkIndex); - network.updateNetworkStats(); + network.updateAttributes(); long packRecv = network.getPacketsRecv(); return new DecimalType(packRecv); } @@ -588,7 +584,7 @@ public DecimalType getNetworkPacketsSent(int networkIndex) throws DeviceNotFound // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 networks = hal.getNetworkIFs(); NetworkIF network = (NetworkIF) getDevice(networks, networkIndex); - network.updateNetworkStats(); + network.updateAttributes(); long packSent = network.getPacketsSent(); return new DecimalType(packSent); } @@ -599,7 +595,7 @@ public DecimalType getNetworkDataSent(int networkIndex) throws DeviceNotFoundExc // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 networks = hal.getNetworkIFs(); NetworkIF network = (NetworkIF) getDevice(networks, networkIndex); - network.updateNetworkStats(); + network.updateAttributes(); long bytesSent = network.getBytesSent(); return new DecimalType(getSizeInMB(bytesSent)); } @@ -610,13 +606,13 @@ public DecimalType getNetworkDataReceived(int networkIndex) throws DeviceNotFoun // In OSHI 4.0.0. it is planned to change this mechanism - see https://github.com/oshi/oshi/issues/310 networks = hal.getNetworkIFs(); NetworkIF network = (NetworkIF) getDevice(networks, networkIndex); - network.updateNetworkStats(); + network.updateAttributes(); long bytesRecv = network.getBytesRecv(); return new DecimalType(getSizeInMB(bytesRecv)); } @Override - public StringType getProcessName(int pid) throws DeviceNotFoundException { + public @Nullable StringType getProcessName(int pid) throws DeviceNotFoundException { if (pid > 0) { OSProcess process = getProcess(pid); String name = process.getName(); @@ -627,7 +623,7 @@ public StringType getProcessName(int pid) throws DeviceNotFoundException { } @Override - public DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException { + public @Nullable DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException { if (pid > 0) { OSProcess process = getProcess(pid); double cpuUsageRaw = (process.getKernelTime() + process.getUserTime()) / process.getUpTime(); @@ -639,7 +635,7 @@ public DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException { } @Override - public DecimalType getProcessMemoryUsage(int pid) throws DeviceNotFoundException { + public @Nullable DecimalType getProcessMemoryUsage(int pid) throws DeviceNotFoundException { if (pid > 0) { OSProcess process = getProcess(pid); long memortInBytes = process.getResidentSetSize(); @@ -651,7 +647,7 @@ public DecimalType getProcessMemoryUsage(int pid) throws DeviceNotFoundException } @Override - public StringType getProcessPath(int pid) throws DeviceNotFoundException { + public @Nullable StringType getProcessPath(int pid) throws DeviceNotFoundException { if (pid > 0) { OSProcess process = getProcess(pid); String path = process.getPath(); @@ -662,7 +658,7 @@ public StringType getProcessPath(int pid) throws DeviceNotFoundException { } @Override - public DecimalType getProcessThreads(int pid) throws DeviceNotFoundException { + public @Nullable DecimalType getProcessThreads(int pid) throws DeviceNotFoundException { if (pid > 0) { OSProcess process = getProcess(pid); int threadCount = process.getThreadCount(); diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java index 2fa397f46557f..8ffdd78334e5c 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.systeminfo.internal.model; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.StringType; @@ -19,7 +21,9 @@ * {@link SysteminfoInterface} defines the methods needed to provide this binding with the required system information. * * @author Svilen Valkanov - Initial contribution + * @author Wouter Born - Add null annotations */ +@NonNullByDefault public interface SysteminfoInterface { /** @@ -67,33 +71,26 @@ public interface SysteminfoInterface { */ public DecimalType getCpuPhysicalCores(); - /** - * Get the recent average CPU load for all logical processors - * - * @return the load as percentage value /0-100/ - */ - public DecimalType getCpuLoad(); - /** * Returns the system load average for the last minute. * * @return the load as a number of processes or null, if no information is available */ - public DecimalType getCpuLoad1(); + public @Nullable DecimalType getCpuLoad1(); /** * Returns the system load average for the last 5 minutes. * * @return the load as number of processes or null, if no information is available */ - public DecimalType getCpuLoad5(); + public @Nullable DecimalType getCpuLoad5(); /** * Returns the system load average for the last 15 minutes. * * @return the load as number of processes or null, if no information is available */ - public DecimalType getCpuLoad15(); + public @Nullable DecimalType getCpuLoad15(); /** * Get the System uptime (time since boot). @@ -136,14 +133,14 @@ public interface SysteminfoInterface { * * @return percent of available memory or null, if no information is available */ - public DecimalType getMemoryAvailablePercent(); + public @Nullable DecimalType getMemoryAvailablePercent(); /** * Percents of used memory on the machine * * @return percent of used memory or null, if no information is available */ - public DecimalType getMemoryUsedPercent(); + public @Nullable DecimalType getMemoryUsedPercent(); // Swap memory info /** @@ -151,35 +148,35 @@ public interface SysteminfoInterface { * * @return memory size in MB or 0, if no there is no swap memory */ - public DecimalType getSwapTotal(); + public @Nullable DecimalType getSwapTotal(); /** * Returns available size swap of memory * * @return memory size in MB or 0, if no there is no swap memory */ - public DecimalType getSwapAvailable(); + public @Nullable DecimalType getSwapAvailable(); /** * Returns used size of swap memory * * @return memory size in MB or 0, if no there is no swap memory */ - public DecimalType getSwapUsed(); + public @Nullable DecimalType getSwapUsed(); /** * Percents of available swap memory on the machine * * @return percent of available memory or null, if no there is no swap memory */ - public DecimalType getSwapAvailablePercent(); + public @Nullable DecimalType getSwapAvailablePercent(); /** * Percents of used swap memory on the machine * * @return percent of used memory or null, if no there is no swap memory */ - public DecimalType getSwapUsedPercent(); + public @Nullable DecimalType getSwapUsedPercent(); // Storage info /** @@ -216,7 +213,7 @@ public interface SysteminfoInterface { * @return percent of available storage or null * @throws DeviceNotFoundException */ - public DecimalType getStorageAvailablePercent(int deviceIndex) throws DeviceNotFoundException; + public @Nullable DecimalType getStorageAvailablePercent(int deviceIndex) throws DeviceNotFoundException; /** * Gets the percent of used storage on the logical volume @@ -225,7 +222,7 @@ public interface SysteminfoInterface { * @return percent of used storage or null * @throws DeviceNotFoundException */ - public DecimalType getStorageUsedPercent(int deviceIndex) throws DeviceNotFoundException; + public @Nullable DecimalType getStorageUsedPercent(int deviceIndex) throws DeviceNotFoundException; /** * Gets the name of the logical storage volume @@ -354,14 +351,14 @@ public interface SysteminfoInterface { * * @return Temperature in degrees Celsius if available, null otherwise. */ - public DecimalType getSensorsCpuTemperature(); + public @Nullable DecimalType getSensorsCpuTemperature(); /** * Get the information for the CPU voltage. * * @return Voltage in Volts if available, null otherwise. */ - public DecimalType getSensorsCpuVoltage(); + public @Nullable DecimalType getSensorsCpuVoltage(); /** * Get fan speed @@ -370,7 +367,7 @@ public interface SysteminfoInterface { * @return Speed in rpm or null if unable to measure fan speed * @throws DeviceNotFoundException */ - public DecimalType getSensorsFanSpeed(int deviceIndex) throws DeviceNotFoundException; + public @Nullable DecimalType getSensorsFanSpeed(int deviceIndex) throws DeviceNotFoundException; // Battery info /** @@ -380,7 +377,7 @@ public interface SysteminfoInterface { * @return minutes remaining charge or null, if the time is estimated as unlimited * @throws DeviceNotFoundException */ - public DecimalType getBatteryRemainingTime(int deviceIndex) throws DeviceNotFoundException; + public @Nullable DecimalType getBatteryRemainingTime(int deviceIndex) throws DeviceNotFoundException; /** * Battery remaining capacity. @@ -405,7 +402,7 @@ public interface SysteminfoInterface { * @param pid - the PID of the process * @throws DeviceNotFoundException - thrown if process with this PID can not be found */ - public StringType getProcessName(int pid) throws DeviceNotFoundException; + public @Nullable StringType getProcessName(int pid) throws DeviceNotFoundException; /** * Returns the CPU usage of the process @@ -414,7 +411,7 @@ public interface SysteminfoInterface { * @return - percentage value /0-100/ * @throws DeviceNotFoundException - thrown if process with this PID can not be found */ - public DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException; + public @Nullable DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException; /** * Returns the size of RAM memory only usage of the process @@ -423,7 +420,7 @@ public interface SysteminfoInterface { * @return memory size in MB * @throws DeviceNotFoundException- thrown if process with this PID can not be found */ - public DecimalType getProcessMemoryUsage(int pid) throws DeviceNotFoundException; + public @Nullable DecimalType getProcessMemoryUsage(int pid) throws DeviceNotFoundException; /** * Returns the full path of the executing process. @@ -431,7 +428,7 @@ public interface SysteminfoInterface { * @param pid - the PID of the process * @throws DeviceNotFoundException - thrown if process with this PID can not be found */ - public StringType getProcessPath(int pid) throws DeviceNotFoundException; + public @Nullable StringType getProcessPath(int pid) throws DeviceNotFoundException; /** * Returns the number of threads in this process. @@ -439,6 +436,6 @@ public interface SysteminfoInterface { * @param pid - the PID of the process * @throws DeviceNotFoundException - thrown if process with this PID can not be found */ - public DecimalType getProcessThreads(int pid) throws DeviceNotFoundException; + public @Nullable DecimalType getProcessThreads(int pid) throws DeviceNotFoundException; } diff --git a/bundles/org.openhab.binding.systeminfo/src/main/resources/ESH-INF/thing/channels.xml b/bundles/org.openhab.binding.systeminfo/src/main/resources/ESH-INF/thing/channels.xml index ee72b7b76cd42..2d633a8953953 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/resources/ESH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.systeminfo/src/main/resources/ESH-INF/thing/channels.xml @@ -104,7 +104,6 @@ - @@ -269,14 +268,6 @@ - - Number - - Load in percent - - - - Number diff --git a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun index b59201a5bbc58..f44e64055a756 100644 --- a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun +++ b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun @@ -54,13 +54,13 @@ Fragment-Host: org.openhab.binding.systeminfo org.apache.servicemix.specs.stax-api-1.2;version='[2.9.0,2.9.1)',\ org.mockito.mockito-core;version='[2.25.0,2.25.1)',\ org.objenesis;version='[2.6.0,2.6.1)',\ - com.github.oshi.oshi-core;version='[3.13.0,3.13.1)',\ - com.sun.jna;version='[5.3.0,5.3.1)',\ - com.sun.jna.platform;version='[5.3.0,5.3.1)',\ org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\ slf4j.api;version='[1.7.25,1.7.26)',\ ch.qos.logback.core;version='[1.2.3,1.2.4)',\ tec.uom.lib.uom-lib-common;version='[1.0.3,1.0.4)',\ tec.uom.se;version='[1.0.10,1.0.11)',\ ch.qos.logback.classic;version='[1.2.3,1.2.4)',\ - org.apache.servicemix.bundles.jaxb-impl;version='[2.2.11,2.2.12)' \ No newline at end of file + org.apache.servicemix.bundles.jaxb-impl;version='[2.2.11,2.2.12)',\ + com.github.oshi.oshi-core;version='[4.0.0,4.0.1)',\ + com.sun.jna;version='[5.4.0,5.4.1)',\ + com.sun.jna.platform;version='[5.4.0,5.4.1)' \ No newline at end of file diff --git a/itests/org.openhab.binding.systeminfo.tests/pom.xml b/itests/org.openhab.binding.systeminfo.tests/pom.xml index ef3847283e3a6..4d86306556de4 100644 --- a/itests/org.openhab.binding.systeminfo.tests/pom.xml +++ b/itests/org.openhab.binding.systeminfo.tests/pom.xml @@ -22,17 +22,17 @@ net.java.dev.jna jna-platform - 5.3.0 + 5.4.0 net.java.dev.jna jna - 5.3.0 + 5.4.0 com.github.oshi oshi-core - 3.13.0 + 4.0.0 org.slf4j diff --git a/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java b/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java index c8bd352320497..10d581de91b7b 100644 --- a/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java +++ b/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java @@ -124,7 +124,9 @@ public void setUp() { // Unbind oshiSystemInfo service and bind the mock service to make the systeminfobinding tests independent of // the external OSHI library - systeminfoHandlerFactory.unbindSystemInfo(oshiSystemInfo); + if (oshiSystemInfo != null) { + systeminfoHandlerFactory.unbindSystemInfo(oshiSystemInfo); + } systeminfoHandlerFactory.bindSystemInfo(mockedSystemInfo); managedThingProvider = getService(ThingProvider.class, ManagedThingProvider.class); @@ -345,18 +347,6 @@ public void assertStateOfSecondDeviceIsUpdated() { assertItemState(acceptedItemType, DEFAULT_TEST_ITEM_NAME, DEFAULT_CHANNEL_TEST_PRIORITY, UnDefType.UNDEF); } - @Test - public void assertChannelCpuLoadIsUpdated() { - String channnelID = SysteminfoBindingConstants.CHANNEL_CPU_LOAD; - String acceptedItemType = "Number"; - - DecimalType mockedCpuLoadValue = new DecimalType(10.5); - when(mockedSystemInfo.getCpuLoad()).thenReturn(mockedCpuLoadValue); - - initializeThingWithChannel(channnelID, acceptedItemType); - assertItemState(acceptedItemType, DEFAULT_TEST_ITEM_NAME, DEFAULT_CHANNEL_TEST_PRIORITY, mockedCpuLoadValue); - } - @Test public void assertChannelCpuLoad1IsUpdated() { String channnelID = SysteminfoBindingConstants.CHANNEL_CPU_LOAD_1;