Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service to suggest addons based on running processes #3904

Merged
merged 7 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bom/openhab-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.config.discovery.addon.process</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.config.discovery.addon.upnp</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="annotationpath" value="target/dependency"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="annotationpath" value="target/dependency"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.core.config.discovery.addon.process</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
14 changes: 14 additions & 0 deletions bundles/org.openhab.core.config.discovery.addon.process/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
This content is produced and maintained by the openHAB project.

* Project home: https://www.openhab.org

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/openhab/openhab-core

29 changes: 29 additions & 0 deletions bundles/org.openhab.core.config.discovery.addon.process/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.reactor.bundles</artifactId>
<version>4.1.0-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.core.config.discovery.addon.process</artifactId>

<name>openHAB Core :: Bundles :: Process-based Suggested Add-on Finder</name>

<dependencies>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.config.discovery.addon</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.addon</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.config.discovery.addon.process;

import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_NAME_PROCESS;
import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_TYPE_PROCESS;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.addon.AddonDiscoveryMethod;
import org.openhab.core.addon.AddonInfo;
import org.openhab.core.addon.AddonMatchProperty;
import org.openhab.core.config.discovery.addon.AddonFinder;
import org.openhab.core.config.discovery.addon.BaseAddonFinder;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This is a {@link ProcessAddonFinder} for finding suggested add-ons by checking processes running
* on the openHAB server.
*
* @author Holger Friedrich - Initial contribution
*/
@NonNullByDefault
@Component(service = AddonFinder.class, name = ProcessAddonFinder.SERVICE_NAME)
public class ProcessAddonFinder extends BaseAddonFinder {

private static final String COMMAND = "command";

public static final String SERVICE_TYPE = SERVICE_TYPE_PROCESS;
Copy link
Contributor

@mherwege mherwege Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can eliminate these constants from AddonFinderConstants.java and define them here instead with the same logic. Only refer to ADDON_SUGGESTION_FINDER in AddonFinderConstants.java.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...but I had to make ADDON_SUGGESTION_FINDER public...

public static final String SERVICE_NAME = SERVICE_NAME_PROCESS;

private final Logger logger = LoggerFactory.getLogger(ProcessAddonFinder.class);

@Activate
public ProcessAddonFinder() {
}

// get list of running processes visible to openHAB,
// also tries to mitigate differences on different operating systems
String getProcessCommandProcess(ProcessHandle h) {
Optional<String> command = h.info().command();
if (command.isPresent())
return command.get();
Optional<String[]> args = h.info().arguments();
if (!args.isPresent())
return "";
String[] argsArray = args.get();
if (argsArray.length < 1)
return "";
return argsArray[0];
}

@Override
public Set<AddonInfo> getSuggestedAddons() {
logger.trace("ProcessAddonFinder::getSuggestedAddons");
Set<AddonInfo> result = new HashSet<>();
Set<String> processList = Collections.emptySet();
try {
processList = ProcessHandle.allProcesses().map(this::getProcessCommandProcess)
.filter(Predicate.not(String::isEmpty)).collect(Collectors.toUnmodifiableSet());
} catch (SecurityException | UnsupportedOperationException unused) {
logger.info("Cannot obtain process list, suggesting add-ons not possible");
kaikreuzer marked this conversation as resolved.
Show resolved Hide resolved
return result;
}
// logging task list is commented out by default due to privacy reasons
// logger.trace("Processes visible: {}", processList.toString());
holgerfriedrich marked this conversation as resolved.
Show resolved Hide resolved

for (AddonInfo candidate : addonCandidates) {
for (AddonDiscoveryMethod method : candidate.getDiscoveryMethods().stream()
.filter(method -> SERVICE_TYPE.equals(method.getServiceType())).toList()) {

List<AddonMatchProperty> matchProperties = method.getMatchProperties();
List<AddonMatchProperty> commands = matchProperties.stream()
.filter(amp -> COMMAND.equals(amp.getName())).collect(Collectors.toUnmodifiableList());

if (matchProperties.size() != commands.size()) {
logger.warn("Add-on '{}' addon.xml file contains unsupported 'match-property'", candidate.getUID());
}

if (commands.isEmpty()) {
logger.warn("Add-on '{}' addon.xml file does not specify match property \"{}\"", candidate.getUID(),
COMMAND);
break;
}

// now check if a process matches the pattern defined in addon.xml
logger.debug("Checking candidate: {}", candidate.getUID());

for (AddonMatchProperty command : commands) {
logger.trace("Candidate {}, pattern \"{}\"", candidate.getUID(), command.getRegex());
boolean match = processList.stream().anyMatch(c -> command.getPattern().matcher(c).matches());

if (match) {
result.add(candidate);
logger.debug("Suggested add-on found: {}", candidate.getUID());
break;
}
}
}
}
return result;
}

@Override
public String getServiceName() {
return SERVICE_NAME;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ public class AddonFinderConstants {
public static final String SERVICE_NAME_MDNS = SERVICE_TYPE_MDNS + ADDON_SUGGESTION_FINDER;
public static final String FEATURE_MDNS = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_MDNS;

public static final String SERVICE_TYPE_PROCESS = "process";
public static final String CFG_FINDER_PROCESS = "suggestionFinderProcess";
holgerfriedrich marked this conversation as resolved.
Show resolved Hide resolved
public static final String SERVICE_NAME_PROCESS = SERVICE_TYPE_PROCESS + ADDON_SUGGESTION_FINDER;
public static final String FEATURE_PROCESS = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_PROCESS;

public static final String SERVICE_TYPE_UPNP = "upnp";
public static final String CFG_FINDER_UPNP = "suggestionFinderUpnp";
public static final String SERVICE_NAME_UPNP = SERVICE_TYPE_UPNP + ADDON_SUGGESTION_FINDER;
public static final String FEATURE_UPNP = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_UPNP;

public static final List<String> SUGGESTION_FINDERS = List.of(SERVICE_NAME_MDNS, SERVICE_NAME_UPNP);
public static final List<String> SUGGESTION_FINDERS = List.of(SERVICE_NAME_MDNS, SERVICE_NAME_PROCESS,
SERVICE_NAME_UPNP);
public static final Map<String, String> SUGGESTION_FINDER_CONFIGS = Map.of(SERVICE_NAME_MDNS, CFG_FINDER_MDNS,
SERVICE_NAME_UPNP, CFG_FINDER_UPNP);
SERVICE_NAME_PROCESS, CFG_FINDER_PROCESS, SERVICE_NAME_UPNP, CFG_FINDER_UPNP);
holgerfriedrich marked this conversation as resolved.
Show resolved Hide resolved
public static final Map<String, String> SUGGESTION_FINDER_FEATURES = Map.of(SERVICE_NAME_MDNS, FEATURE_MDNS,
SERVICE_NAME_UPNP, FEATURE_UPNP);
SERVICE_NAME_PROCESS, FEATURE_PROCESS, SERVICE_NAME_UPNP, FEATURE_UPNP);
}
1 change: 1 addition & 0 deletions bundles/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<module>org.openhab.core.config.discovery</module>
<module>org.openhab.core.config.discovery.addon</module>
<module>org.openhab.core.config.discovery.addon.mdns</module>
<module>org.openhab.core.config.discovery.addon.process</module>
<module>org.openhab.core.config.discovery.addon.upnp</module>
<module>org.openhab.core.config.discovery.mdns</module>
<module>org.openhab.core.config.discovery.usbserial</module>
Expand Down
6 changes: 6 additions & 0 deletions features/karaf/openhab-core/src/main/feature/feature.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@
<feature dependency="true">openhab.tp-jmdns</feature>
</feature>

<feature name="openhab-core-config-discovery-addon-process" version="${project.version}">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you add this feature to openhab-runtime-base you will not need to add this finder to the constants in AddonFinderConstants.java. The feature will then automatically get installed and not through the service. The only reason to do it through the service is to allow enabling/disabling.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think someone did already ask to have enabling/disabling. ??

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, that's conditional. If retrieving the processes is too high a load, we should. Otherwise I don't see the point. Right now, the implementation does not cache anything and does a call to retrieve the processes any time the suggestions are retrieved. If that is quick, no need to enable/disable a little piece of code. There is nothing running in the background in separate threads either.
@kaikreuzer Did not react on my feedback on it. If he feels strongly, then, of course it needs to be there, but it should also be added to the configuration parameters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mherwege I am OK with that.

Copy link
Member Author

@holgerfriedrich holgerfriedrich Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done as suggested, just did the verification - still works

<feature>openhab-core-base</feature>
<feature>openhab-core-config-discovery-addon</feature>
<bundle>mvn:org.openhab.core.bundles/org.openhab.core.config.discovery.addon.process/${project.version}</bundle>
</feature>

<feature name="openhab-core-config-discovery-addon-upnp" version="${project.version}">
<feature>openhab-core-base</feature>
<feature>openhab-core-config-discovery-addon</feature>
Expand Down