mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-26 12:11:33 +01:00
Add a new optional input parameter to discovery services (#4389)
Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
47284e5521
commit
b8b3ec9df0
@ -49,6 +49,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
* @author Kai Kreuzer - Refactored API
|
* @author Kai Kreuzer - Refactored API
|
||||||
* @author Dennis Nobel - Added background discovery configuration through Configuration Admin
|
* @author Dennis Nobel - Added background discovery configuration through Configuration Admin
|
||||||
* @author Andre Fuechsel - Added removeOlderResults
|
* @author Andre Fuechsel - Added removeOlderResults
|
||||||
|
* @author Laurent Garnier - Added discovery with an optional input parameter
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class AbstractDiscoveryService implements DiscoveryService {
|
public abstract class AbstractDiscoveryService implements DiscoveryService {
|
||||||
@ -64,6 +65,9 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
|
|
||||||
private boolean backgroundDiscoveryEnabled;
|
private boolean backgroundDiscoveryEnabled;
|
||||||
|
|
||||||
|
private @Nullable String scanInputLabel;
|
||||||
|
private @Nullable String scanInputDescription;
|
||||||
|
|
||||||
private final Map<ThingUID, DiscoveryResult> cachedResults = new HashMap<>();
|
private final Map<ThingUID, DiscoveryResult> cachedResults = new HashMap<>();
|
||||||
|
|
||||||
private final Set<ThingTypeUID> supportedThingTypes;
|
private final Set<ThingTypeUID> supportedThingTypes;
|
||||||
@ -84,20 +88,44 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
* service automatically stops its forced discovery process (>= 0).
|
* service automatically stops its forced discovery process (>= 0).
|
||||||
* @param backgroundDiscoveryEnabledByDefault defines, whether the default for this discovery service is to
|
* @param backgroundDiscoveryEnabledByDefault defines, whether the default for this discovery service is to
|
||||||
* enable background discovery or not.
|
* enable background discovery or not.
|
||||||
|
* @param scanInputLabel the label of the optional input parameter to start the discovery or null if no input
|
||||||
|
* parameter supported
|
||||||
|
* @param scanInputDescription the description of the optional input parameter to start the discovery or null if no
|
||||||
|
* input parameter supported
|
||||||
* @throws IllegalArgumentException if {@code timeout < 0}
|
* @throws IllegalArgumentException if {@code timeout < 0}
|
||||||
*/
|
*/
|
||||||
protected AbstractDiscoveryService(@Nullable Set<ThingTypeUID> supportedThingTypes, int timeout,
|
protected AbstractDiscoveryService(@Nullable Set<ThingTypeUID> supportedThingTypes, int timeout,
|
||||||
boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
|
boolean backgroundDiscoveryEnabledByDefault, @Nullable String scanInputLabel,
|
||||||
|
@Nullable String scanInputDescription) throws IllegalArgumentException {
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
throw new IllegalArgumentException("The timeout must be >= 0!");
|
throw new IllegalArgumentException("The timeout must be >= 0!");
|
||||||
}
|
}
|
||||||
this.supportedThingTypes = supportedThingTypes == null ? Set.of() : Set.copyOf(supportedThingTypes);
|
this.supportedThingTypes = supportedThingTypes == null ? Set.of() : Set.copyOf(supportedThingTypes);
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.backgroundDiscoveryEnabled = backgroundDiscoveryEnabledByDefault;
|
this.backgroundDiscoveryEnabled = backgroundDiscoveryEnabledByDefault;
|
||||||
|
this.scanInputLabel = scanInputLabel;
|
||||||
|
this.scanInputDescription = scanInputDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of this class with the specified parameters and background discovery enabled.
|
* Creates a new instance of this class with the specified parameters and no input parameter supported to start the
|
||||||
|
* discovery.
|
||||||
|
*
|
||||||
|
* @param supportedThingTypes the list of Thing types which are supported (can be null)
|
||||||
|
* @param timeout the discovery timeout in seconds after which the discovery
|
||||||
|
* service automatically stops its forced discovery process (>= 0).
|
||||||
|
* @param backgroundDiscoveryEnabledByDefault defines, whether the default for this discovery service is to
|
||||||
|
* enable background discovery or not.
|
||||||
|
* @throws IllegalArgumentException if {@code timeout < 0}
|
||||||
|
*/
|
||||||
|
protected AbstractDiscoveryService(@Nullable Set<ThingTypeUID> supportedThingTypes, int timeout,
|
||||||
|
boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
|
||||||
|
this(supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of this class with the specified parameters and background discovery enabled
|
||||||
|
* and no input parameter supported to start the discovery.
|
||||||
*
|
*
|
||||||
* @param supportedThingTypes the list of Thing types which are supported (can be null)
|
* @param supportedThingTypes the list of Thing types which are supported (can be null)
|
||||||
* @param timeout the discovery timeout in seconds after which the discovery service
|
* @param timeout the discovery timeout in seconds after which the discovery service
|
||||||
@ -111,7 +139,8 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of this class with the specified parameters and background discovery enabled.
|
* Creates a new instance of this class with the specified parameters and background discovery enabled
|
||||||
|
* and no input parameter supported to start the discovery.
|
||||||
*
|
*
|
||||||
* @param timeout the discovery timeout in seconds after which the discovery service
|
* @param timeout the discovery timeout in seconds after which the discovery service
|
||||||
* automatically stops its forced discovery process (>= 0).
|
* automatically stops its forced discovery process (>= 0).
|
||||||
@ -133,6 +162,21 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
return supportedThingTypes;
|
return supportedThingTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScanInputSupported() {
|
||||||
|
return scanInputLabel != null && scanInputDescription != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getScanInputLabel() {
|
||||||
|
return scanInputLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getScanInputDescription() {
|
||||||
|
return scanInputDescription;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount of time in seconds after which the discovery service automatically
|
* Returns the amount of time in seconds after which the discovery service automatically
|
||||||
* stops its forced discovery process.
|
* stops its forced discovery process.
|
||||||
@ -168,7 +212,16 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void startScan(@Nullable ScanListener listener) {
|
public void startScan(@Nullable ScanListener listener) {
|
||||||
|
startScanInternal(null, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startScan(String input, @Nullable ScanListener listener) {
|
||||||
|
startScanInternal(input, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void startScanInternal(@Nullable String input, @Nullable ScanListener listener) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
// we first stop any currently running scan and its scheduled stop
|
// we first stop any currently running scan and its scheduled stop
|
||||||
// call
|
// call
|
||||||
@ -194,7 +247,11 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
timestampOfLastScan = Instant.now();
|
timestampOfLastScan = Instant.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startScan();
|
if (isScanInputSupported() && input != null) {
|
||||||
|
startScan(input);
|
||||||
|
} else {
|
||||||
|
startScan();
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
scheduledStop = this.scheduledStop;
|
scheduledStop = this.scheduledStop;
|
||||||
if (scheduledStop != null) {
|
if (scheduledStop != null) {
|
||||||
@ -232,6 +289,11 @@ public abstract class AbstractDiscoveryService implements DiscoveryService {
|
|||||||
*/
|
*/
|
||||||
protected abstract void startScan();
|
protected abstract void startScan();
|
||||||
|
|
||||||
|
// An abstract method would have required a change in all existing bindings implementing a DiscoveryService
|
||||||
|
protected void startScan(String input) {
|
||||||
|
logger.warn("Discovery with input parameter not implemented by service '{}'!", this.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method cleans up after a scan, i.e. it removes listeners and other required operations.
|
* This method cleans up after a scan, i.e. it removes listeners and other required operations.
|
||||||
*/
|
*/
|
||||||
|
@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
* It handles the injection of the {@link ThingHandler}
|
* It handles the injection of the {@link ThingHandler}
|
||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
|
* @author Laurent Garnier - Added discovery with an optional input parameter
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class AbstractThingHandlerDiscoveryService<T extends ThingHandler> extends AbstractDiscoveryService
|
public abstract class AbstractThingHandlerDiscoveryService<T extends ThingHandler> extends AbstractDiscoveryService
|
||||||
@ -45,12 +46,18 @@ public abstract class AbstractThingHandlerDiscoveryService<T extends ThingHandle
|
|||||||
protected @NonNullByDefault({}) T thingHandler = (@NonNull T) null;
|
protected @NonNullByDefault({}) T thingHandler = (@NonNull T) null;
|
||||||
|
|
||||||
protected AbstractThingHandlerDiscoveryService(Class<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
protected AbstractThingHandlerDiscoveryService(Class<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
||||||
int timeout, boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
|
int timeout, boolean backgroundDiscoveryEnabledByDefault, @Nullable String scanInputLabel,
|
||||||
super(supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault);
|
@Nullable String scanInputDescription) throws IllegalArgumentException {
|
||||||
|
super(supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault, scanInputLabel, scanInputDescription);
|
||||||
this.thingClazz = thingClazz;
|
this.thingClazz = thingClazz;
|
||||||
this.backgroundDiscoveryEnabled = backgroundDiscoveryEnabledByDefault;
|
this.backgroundDiscoveryEnabled = backgroundDiscoveryEnabledByDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected AbstractThingHandlerDiscoveryService(Class<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
||||||
|
int timeout, boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
|
||||||
|
this(thingClazz, supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
protected AbstractThingHandlerDiscoveryService(Class<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
protected AbstractThingHandlerDiscoveryService(Class<T> thingClazz, @Nullable Set<ThingTypeUID> supportedThingTypes,
|
||||||
int timeout) throws IllegalArgumentException {
|
int timeout) throws IllegalArgumentException {
|
||||||
this(thingClazz, supportedThingTypes, timeout, true);
|
this(thingClazz, supportedThingTypes, timeout, true);
|
||||||
|
@ -39,6 +39,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
* @author Michael Grammling - Initial contribution
|
* @author Michael Grammling - Initial contribution
|
||||||
* @author Kai Kreuzer - Refactored API
|
* @author Kai Kreuzer - Refactored API
|
||||||
* @author Dennis Nobel - Added background discovery configuration through Configuration Admin
|
* @author Dennis Nobel - Added background discovery configuration through Configuration Admin
|
||||||
|
* @author Laurent Garnier - Added discovery with an optional input parameter
|
||||||
*
|
*
|
||||||
* @see DiscoveryListener
|
* @see DiscoveryListener
|
||||||
* @see DiscoveryServiceRegistry
|
* @see DiscoveryServiceRegistry
|
||||||
@ -60,6 +61,31 @@ public interface DiscoveryService {
|
|||||||
*/
|
*/
|
||||||
Collection<ThingTypeUID> getSupportedThingTypes();
|
Collection<ThingTypeUID> getSupportedThingTypes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the discovery supports an optional input parameter to run, otherwise {@code false}.
|
||||||
|
*
|
||||||
|
* @return true if the discovery supports an optional input parameter to run, otherwise false
|
||||||
|
*/
|
||||||
|
boolean isScanInputSupported();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label of the supported input parameter to start the discovery.
|
||||||
|
*
|
||||||
|
* @return the label of the supported input parameter to start the discovery or null if input parameter not
|
||||||
|
* supported
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String getScanInputLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of the supported input parameter to start the discovery.
|
||||||
|
*
|
||||||
|
* @return the description of the supported input parameter to start the discovery or null if input parameter not
|
||||||
|
* supported
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String getScanInputDescription();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount of time in seconds after which an active scan ends.
|
* Returns the amount of time in seconds after which an active scan ends.
|
||||||
*
|
*
|
||||||
@ -87,6 +113,20 @@ public interface DiscoveryService {
|
|||||||
*/
|
*/
|
||||||
void startScan(@Nullable ScanListener listener);
|
void startScan(@Nullable ScanListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers this service to start an active scan for new devices using an input parameter for that.<br>
|
||||||
|
* This method must not block any calls such as {@link #abortScan()} and
|
||||||
|
* must return fast.
|
||||||
|
* <p>
|
||||||
|
* If started, any registered {@link DiscoveryListener} must be notified about {@link DiscoveryResult}s.
|
||||||
|
* <p>
|
||||||
|
* If there is already a scan running, it is aborted and a new scan is triggered.
|
||||||
|
*
|
||||||
|
* @param input an input parameter to be used during discovery scan
|
||||||
|
* @param listener a listener that is notified about errors or termination of the scan
|
||||||
|
*/
|
||||||
|
void startScan(String input, @Nullable ScanListener listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops an active scan for devices.<br>
|
* Stops an active scan for devices.<br>
|
||||||
* This method must not block any calls such as {@link #startScan} and must
|
* This method must not block any calls such as {@link #startScan} and must
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
package org.openhab.core.config.discovery;
|
package org.openhab.core.config.discovery;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
@ -29,6 +30,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
*
|
*
|
||||||
* @author Michael Grammling - Initial contribution
|
* @author Michael Grammling - Initial contribution
|
||||||
* @author Ivaylo Ivanov - Added getMaxScanTimeout
|
* @author Ivaylo Ivanov - Added getMaxScanTimeout
|
||||||
|
* @author Laurent Garnier - Added discovery with an optional input parameter
|
||||||
*
|
*
|
||||||
* @see DiscoveryService
|
* @see DiscoveryService
|
||||||
* @see DiscoveryListener
|
* @see DiscoveryListener
|
||||||
@ -44,6 +46,7 @@ public interface DiscoveryServiceRegistry {
|
|||||||
*
|
*
|
||||||
* @param thingTypeUID the Thing type UID pointing to collection of discovery
|
* @param thingTypeUID the Thing type UID pointing to collection of discovery
|
||||||
* services to be forced to start a discovery
|
* services to be forced to start a discovery
|
||||||
|
* @param input an optional input parameter to be used during discovery scan, can be null.
|
||||||
* @param listener a callback to inform about errors or termination, can be null.
|
* @param listener a callback to inform about errors or termination, can be null.
|
||||||
* If more than one discovery service is started, the {@link ScanListener#onFinished()} callback is
|
* If more than one discovery service is started, the {@link ScanListener#onFinished()} callback is
|
||||||
* called after all
|
* called after all
|
||||||
@ -54,7 +57,7 @@ public interface DiscoveryServiceRegistry {
|
|||||||
* @return true if a t least one discovery service could be found and forced
|
* @return true if a t least one discovery service could be found and forced
|
||||||
* to start a discovery, otherwise false
|
* to start a discovery, otherwise false
|
||||||
*/
|
*/
|
||||||
boolean startScan(ThingTypeUID thingTypeUID, @Nullable ScanListener listener);
|
boolean startScan(ThingTypeUID thingTypeUID, @Nullable String input, @Nullable ScanListener listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces the associated {@link DiscoveryService}s to start a discovery for
|
* Forces the associated {@link DiscoveryService}s to start a discovery for
|
||||||
@ -65,6 +68,7 @@ public interface DiscoveryServiceRegistry {
|
|||||||
*
|
*
|
||||||
* @param bindingId the binding id pointing to one or more discovery services to
|
* @param bindingId the binding id pointing to one or more discovery services to
|
||||||
* be forced to start a discovery
|
* be forced to start a discovery
|
||||||
|
* @param input an optional input parameter to be used during discovery scan, can be null.
|
||||||
* @param listener a callback to inform about errors or termination, can be null.
|
* @param listener a callback to inform about errors or termination, can be null.
|
||||||
* If more than one discovery service is started, the {@link ScanListener#onFinished()} callback is
|
* If more than one discovery service is started, the {@link ScanListener#onFinished()} callback is
|
||||||
* called after all
|
* called after all
|
||||||
@ -75,7 +79,7 @@ public interface DiscoveryServiceRegistry {
|
|||||||
* @return true if a t least one discovery service could be found and forced
|
* @return true if a t least one discovery service could be found and forced
|
||||||
* to start a discovery, otherwise false
|
* to start a discovery, otherwise false
|
||||||
*/
|
*/
|
||||||
boolean startScan(String bindingId, @Nullable ScanListener listener);
|
boolean startScan(String bindingId, @Nullable String input, @Nullable ScanListener listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts a started discovery on all {@link DiscoveryService}s for the given
|
* Aborts a started discovery on all {@link DiscoveryService}s for the given
|
||||||
@ -163,6 +167,13 @@ public interface DiscoveryServiceRegistry {
|
|||||||
*/
|
*/
|
||||||
List<String> getSupportedBindings();
|
List<String> getSupportedBindings();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of all {@link DiscoveryService}s, that discover thing types of the given binding id.
|
||||||
|
*
|
||||||
|
* @return list of discovery services, that discover thing types of the given binding id
|
||||||
|
*/
|
||||||
|
Set<DiscoveryService> getDiscoveryServices(String bindingId) throws IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum discovery timeout from all discovery services registered for the specified thingTypeUID
|
* Returns the maximum discovery timeout from all discovery services registered for the specified thingTypeUID
|
||||||
*
|
*
|
||||||
|
@ -56,6 +56,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
* @author Kai Kreuzer - Refactored API
|
* @author Kai Kreuzer - Refactored API
|
||||||
* @author Andre Fuechsel - Added removeOlderResults
|
* @author Andre Fuechsel - Added removeOlderResults
|
||||||
* @author Ivaylo Ivanov - Added getMaxScanTimeout
|
* @author Ivaylo Ivanov - Added getMaxScanTimeout
|
||||||
|
* @author Laurent Garnier - Added discovery with an optional input parameter
|
||||||
*
|
*
|
||||||
* @see DiscoveryServiceRegistry
|
* @see DiscoveryServiceRegistry
|
||||||
* @see DiscoveryListener
|
* @see DiscoveryListener
|
||||||
@ -189,7 +190,8 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startScan(ThingTypeUID thingTypeUID, @Nullable ScanListener listener) throws IllegalStateException {
|
public boolean startScan(ThingTypeUID thingTypeUID, @Nullable String input, @Nullable ScanListener listener)
|
||||||
|
throws IllegalStateException {
|
||||||
Set<DiscoveryService> discoveryServicesForThingType = getDiscoveryServices(thingTypeUID);
|
Set<DiscoveryService> discoveryServicesForThingType = getDiscoveryServices(thingTypeUID);
|
||||||
|
|
||||||
if (discoveryServicesForThingType.isEmpty()) {
|
if (discoveryServicesForThingType.isEmpty()) {
|
||||||
@ -197,11 +199,12 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return startScans(discoveryServicesForThingType, listener);
|
return startScans(discoveryServicesForThingType, input, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startScan(String bindingId, final @Nullable ScanListener listener) throws IllegalStateException {
|
public boolean startScan(String bindingId, @Nullable String input, @Nullable ScanListener listener)
|
||||||
|
throws IllegalStateException {
|
||||||
final Set<DiscoveryService> discoveryServicesForBinding = getDiscoveryServices(bindingId);
|
final Set<DiscoveryService> discoveryServicesForBinding = getDiscoveryServices(bindingId);
|
||||||
|
|
||||||
if (discoveryServicesForBinding.isEmpty()) {
|
if (discoveryServicesForBinding.isEmpty()) {
|
||||||
@ -209,7 +212,7 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return startScans(discoveryServicesForBinding, listener);
|
return startScans(discoveryServicesForBinding, input, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -326,7 +329,8 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
return allServicesAborted;
|
return allServicesAborted;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean startScans(Set<DiscoveryService> discoveryServices, @Nullable ScanListener listener) {
|
private boolean startScans(Set<DiscoveryService> discoveryServices, @Nullable String input,
|
||||||
|
@Nullable ScanListener listener) {
|
||||||
boolean atLeastOneDiscoveryServiceHasBeenStarted = false;
|
boolean atLeastOneDiscoveryServiceHasBeenStarted = false;
|
||||||
|
|
||||||
if (discoveryServices.size() > 1) {
|
if (discoveryServices.size() > 1) {
|
||||||
@ -334,7 +338,7 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
AggregatingScanListener aggregatingScanListener = new AggregatingScanListener(discoveryServices.size(),
|
AggregatingScanListener aggregatingScanListener = new AggregatingScanListener(discoveryServices.size(),
|
||||||
listener);
|
listener);
|
||||||
for (DiscoveryService discoveryService : discoveryServices) {
|
for (DiscoveryService discoveryService : discoveryServices) {
|
||||||
if (startScan(discoveryService, aggregatingScanListener)) {
|
if (startScan(discoveryService, input, aggregatingScanListener)) {
|
||||||
atLeastOneDiscoveryServiceHasBeenStarted = true;
|
atLeastOneDiscoveryServiceHasBeenStarted = true;
|
||||||
} else {
|
} else {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@ -343,7 +347,7 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (startScan(discoveryServices.iterator().next(), listener)) {
|
if (startScan(discoveryServices.iterator().next(), input, listener)) {
|
||||||
atLeastOneDiscoveryServiceHasBeenStarted = true;
|
atLeastOneDiscoveryServiceHasBeenStarted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -351,13 +355,18 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
return atLeastOneDiscoveryServiceHasBeenStarted;
|
return atLeastOneDiscoveryServiceHasBeenStarted;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean startScan(DiscoveryService discoveryService, @Nullable ScanListener listener) {
|
private boolean startScan(DiscoveryService discoveryService, @Nullable String input,
|
||||||
|
@Nullable ScanListener listener) {
|
||||||
Collection<ThingTypeUID> supportedThingTypes = discoveryService.getSupportedThingTypes();
|
Collection<ThingTypeUID> supportedThingTypes = discoveryService.getSupportedThingTypes();
|
||||||
try {
|
try {
|
||||||
logger.debug("Triggering scan for thing types '{}' on '{}'...", supportedThingTypes,
|
logger.debug("Triggering scan for thing types '{}' on '{}'...", supportedThingTypes,
|
||||||
discoveryService.getClass().getSimpleName());
|
discoveryService.getClass().getSimpleName());
|
||||||
|
|
||||||
discoveryService.startScan(listener);
|
if (discoveryService.isScanInputSupported() && input != null) {
|
||||||
|
discoveryService.startScan(input, listener);
|
||||||
|
} else {
|
||||||
|
discoveryService.startScan(listener);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Cannot trigger scan for thing types '{}' on '{}'!", supportedThingTypes,
|
logger.error("Cannot trigger scan for thing types '{}' on '{}'!", supportedThingTypes,
|
||||||
@ -380,7 +389,8 @@ public final class DiscoveryServiceRegistryImpl implements DiscoveryServiceRegis
|
|||||||
return discoveryServices;
|
return discoveryServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized Set<DiscoveryService> getDiscoveryServices(String bindingId) throws IllegalStateException {
|
@Override
|
||||||
|
public synchronized Set<DiscoveryService> getDiscoveryServices(String bindingId) throws IllegalStateException {
|
||||||
Set<DiscoveryService> discoveryServices = new HashSet<>();
|
Set<DiscoveryService> discoveryServices = new HashSet<>();
|
||||||
|
|
||||||
for (DiscoveryService discoveryService : this.discoveryServices) {
|
for (DiscoveryService discoveryService : this.discoveryServices) {
|
||||||
|
@ -18,6 +18,7 @@ import java.util.Hashtable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
import org.openhab.core.config.discovery.DiscoveryService;
|
||||||
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
||||||
import org.openhab.core.io.console.Console;
|
import org.openhab.core.io.console.Console;
|
||||||
@ -37,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Kai Kreuzer - Initial contribution
|
* @author Kai Kreuzer - Initial contribution
|
||||||
* @author Dennis Nobel - Added background discovery commands
|
* @author Dennis Nobel - Added background discovery commands
|
||||||
|
* @author Laurent Garnier - Updated command to start discovery with a new optional input parameter
|
||||||
*/
|
*/
|
||||||
@Component(immediate = true, service = ConsoleCommandExtension.class)
|
@Component(immediate = true, service = ConsoleCommandExtension.class)
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
@ -69,9 +71,9 @@ public class DiscoveryConsoleCommandExtension extends AbstractConsoleCommandExte
|
|||||||
String arg1 = args[1];
|
String arg1 = args[1];
|
||||||
if (arg1.contains(":")) {
|
if (arg1.contains(":")) {
|
||||||
ThingTypeUID thingTypeUID = new ThingTypeUID(arg1);
|
ThingTypeUID thingTypeUID = new ThingTypeUID(arg1);
|
||||||
runDiscoveryForThingType(console, thingTypeUID);
|
runDiscoveryForThingType(console, thingTypeUID, args.length > 2 ? args[2] : null);
|
||||||
} else {
|
} else {
|
||||||
runDiscoveryForBinding(console, arg1);
|
runDiscoveryForBinding(console, arg1, args.length > 2 ? args[2] : null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.println("Specify thing type id or binding id to discover: discovery "
|
console.println("Specify thing type id or binding id to discover: discovery "
|
||||||
@ -123,18 +125,18 @@ public class DiscoveryConsoleCommandExtension extends AbstractConsoleCommandExte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runDiscoveryForThingType(Console console, ThingTypeUID thingTypeUID) {
|
private void runDiscoveryForThingType(Console console, ThingTypeUID thingTypeUID, @Nullable String input) {
|
||||||
discoveryServiceRegistry.startScan(thingTypeUID, null);
|
discoveryServiceRegistry.startScan(thingTypeUID, input, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runDiscoveryForBinding(Console console, String bindingId) {
|
private void runDiscoveryForBinding(Console console, String bindingId, @Nullable String input) {
|
||||||
discoveryServiceRegistry.startScan(bindingId, null);
|
discoveryServiceRegistry.startScan(bindingId, input, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getUsages() {
|
public List<String> getUsages() {
|
||||||
return List.of(
|
return List.of(
|
||||||
buildCommandUsage(SUBCMD_START + " <thingTypeUID|bindingID>",
|
buildCommandUsage(SUBCMD_START + " <thingTypeUID|bindingID> [<code>]",
|
||||||
"runs a discovery on a given thing type or binding"),
|
"runs a discovery on a given thing type or binding"),
|
||||||
buildCommandUsage(SUBCMD_BACKGROUND_DISCOVERY_ENABLE + " <PID>",
|
buildCommandUsage(SUBCMD_BACKGROUND_DISCOVERY_ENABLE + " <PID>",
|
||||||
"enables background discovery for the discovery service with the given PID"),
|
"enables background discovery for the discovery service with the given PID"),
|
||||||
|
@ -15,7 +15,7 @@ package org.openhab.core.config.discovery;
|
|||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.collection.IsMapContaining.hasEntry;
|
import static org.hamcrest.collection.IsMapContaining.hasEntry;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -35,6 +35,7 @@ import org.osgi.framework.Bundle;
|
|||||||
* Tests the {@link DiscoveryResultBuilder}.
|
* Tests the {@link DiscoveryResultBuilder}.
|
||||||
*
|
*
|
||||||
* @author Laurent Garnier - Initial contribution
|
* @author Laurent Garnier - Initial contribution
|
||||||
|
* @author Laurent Garnier - Added test for discovery with an input parameter
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
||||||
@ -46,6 +47,7 @@ public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
|||||||
private static final ThingUID THING_UID2 = new ThingUID(THING_TYPE_UID, "thingId2");
|
private static final ThingUID THING_UID2 = new ThingUID(THING_TYPE_UID, "thingId2");
|
||||||
private static final ThingUID THING_UID3 = new ThingUID(THING_TYPE_UID, BRIDGE_UID, "thingId3");
|
private static final ThingUID THING_UID3 = new ThingUID(THING_TYPE_UID, BRIDGE_UID, "thingId3");
|
||||||
private static final ThingUID THING_UID4 = new ThingUID(THING_TYPE_UID, "thingId4");
|
private static final ThingUID THING_UID4 = new ThingUID(THING_TYPE_UID, "thingId4");
|
||||||
|
private static final ThingUID THING_UID5 = new ThingUID(THING_TYPE_UID, BRIDGE_UID, "thingId5");
|
||||||
private static final String KEY1 = "key1";
|
private static final String KEY1 = "key1";
|
||||||
private static final String KEY2 = "key2";
|
private static final String KEY2 = "key2";
|
||||||
private static final String VALUE1 = "value1";
|
private static final String VALUE1 = "value1";
|
||||||
@ -58,9 +60,12 @@ public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
|||||||
private static final String DISCOVERY_LABEL = "Result Test";
|
private static final String DISCOVERY_LABEL = "Result Test";
|
||||||
private static final String DISCOVERY_LABEL_KEY1 = "@text/test";
|
private static final String DISCOVERY_LABEL_KEY1 = "@text/test";
|
||||||
private static final String DISCOVERY_LABEL_KEY2 = "@text/test2 [ \"50\", \"number\" ]";
|
private static final String DISCOVERY_LABEL_KEY2 = "@text/test2 [ \"50\", \"number\" ]";
|
||||||
|
private static final String DISCOVERY_LABEL_CODE = "Result Test with pairing code";
|
||||||
private static final String PROPERTY_LABEL1 = "Label from property (text key)";
|
private static final String PROPERTY_LABEL1 = "Label from property (text key)";
|
||||||
private static final String PROPERTY_LABEL2 = "Label from property (infered key)";
|
private static final String PROPERTY_LABEL2 = "Label from property (infered key)";
|
||||||
private static final String PROPERTY_LABEL3 = "Label from property (parameters 50 and number)";
|
private static final String PROPERTY_LABEL3 = "Label from property (parameters 50 and number)";
|
||||||
|
private static final String PAIRING_CODE_LABEL = "Pairing Code";
|
||||||
|
private static final String PAIRING_CODE_DESCR = "The pairing code";
|
||||||
|
|
||||||
private TranslationProvider i18nProvider = new TranslationProvider() {
|
private TranslationProvider i18nProvider = new TranslationProvider() {
|
||||||
@Override
|
@Override
|
||||||
@ -134,6 +139,28 @@ public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestDiscoveryServiceWithRequiredCode extends AbstractDiscoveryService {
|
||||||
|
|
||||||
|
public TestDiscoveryServiceWithRequiredCode(TranslationProvider i18nProvider, LocaleProvider localeProvider)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
super(Set.of(THING_TYPE_UID), 1, false, PAIRING_CODE_LABEL, PAIRING_CODE_DESCR);
|
||||||
|
this.i18nProvider = i18nProvider;
|
||||||
|
this.localeProvider = localeProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startScan() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startScan(String input) {
|
||||||
|
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(THING_UID5).withThingType(THING_TYPE_UID)
|
||||||
|
.withProperties(properties).withRepresentationProperty(KEY1).withBridge(BRIDGE_UID)
|
||||||
|
.withLabel(DISCOVERY_LABEL_CODE).build();
|
||||||
|
thingDiscovered(discoveryResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
|
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
|
||||||
assertThat(result.getThingTypeUID(), is(THING_TYPE_UID));
|
assertThat(result.getThingTypeUID(), is(THING_TYPE_UID));
|
||||||
@ -156,6 +183,9 @@ public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
|||||||
} else if (THING_UID4.equals(result.getThingUID())) {
|
} else if (THING_UID4.equals(result.getThingUID())) {
|
||||||
assertNull(result.getBridgeUID());
|
assertNull(result.getBridgeUID());
|
||||||
assertThat(result.getLabel(), is(PROPERTY_LABEL3));
|
assertThat(result.getLabel(), is(PROPERTY_LABEL3));
|
||||||
|
} else if (THING_UID5.equals(result.getThingUID())) {
|
||||||
|
assertThat(result.getBridgeUID(), is(BRIDGE_UID));
|
||||||
|
assertThat(result.getLabel(), is(DISCOVERY_LABEL_CODE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +202,21 @@ public class AbstractDiscoveryServiceTest implements DiscoveryListener {
|
|||||||
@Test
|
@Test
|
||||||
public void testDiscoveryResults() {
|
public void testDiscoveryResults() {
|
||||||
TestDiscoveryService discoveryService = new TestDiscoveryService(i18nProvider, localeProvider);
|
TestDiscoveryService discoveryService = new TestDiscoveryService(i18nProvider, localeProvider);
|
||||||
|
assertFalse(discoveryService.isScanInputSupported());
|
||||||
|
assertNull(discoveryService.getScanInputLabel());
|
||||||
|
assertNull(discoveryService.getScanInputDescription());
|
||||||
discoveryService.addDiscoveryListener(this);
|
discoveryService.addDiscoveryListener(this);
|
||||||
discoveryService.startScan();
|
discoveryService.startScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDiscoveryResultsWhenCodeRequired() {
|
||||||
|
TestDiscoveryServiceWithRequiredCode discoveryService = new TestDiscoveryServiceWithRequiredCode(i18nProvider,
|
||||||
|
localeProvider);
|
||||||
|
assertTrue(discoveryService.isScanInputSupported());
|
||||||
|
assertThat(discoveryService.getScanInputLabel(), is(PAIRING_CODE_LABEL));
|
||||||
|
assertThat(discoveryService.getScanInputDescription(), is(PAIRING_CODE_DESCR));
|
||||||
|
discoveryService.addDiscoveryListener(this);
|
||||||
|
discoveryService.startScan("code");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2024 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.io.rest.core.discovery;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a data transfer object that is used to serialize the information about binding discovery.
|
||||||
|
*
|
||||||
|
* @author Laurent Garnier - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class DiscoveryInfoDTO {
|
||||||
|
|
||||||
|
public boolean inputSupported;
|
||||||
|
public @Nullable String inputLabel;
|
||||||
|
public @Nullable String inputDescription;
|
||||||
|
|
||||||
|
public DiscoveryInfoDTO(boolean inputSupported, @Nullable String inputLabel, @Nullable String inputDescription) {
|
||||||
|
this.inputSupported = inputSupported;
|
||||||
|
this.inputLabel = inputLabel;
|
||||||
|
this.inputDescription = inputDescription;
|
||||||
|
}
|
||||||
|
}
|
@ -14,23 +14,37 @@ package org.openhab.core.io.rest.core.internal.discovery;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
import javax.annotation.security.RolesAllowed;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.HeaderParam;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.auth.Role;
|
import org.openhab.core.auth.Role;
|
||||||
|
import org.openhab.core.config.discovery.DiscoveryService;
|
||||||
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
||||||
import org.openhab.core.config.discovery.ScanListener;
|
import org.openhab.core.config.discovery.ScanListener;
|
||||||
|
import org.openhab.core.i18n.I18nUtil;
|
||||||
|
import org.openhab.core.i18n.TranslationProvider;
|
||||||
|
import org.openhab.core.io.rest.JSONResponse;
|
||||||
|
import org.openhab.core.io.rest.LocaleService;
|
||||||
import org.openhab.core.io.rest.RESTConstants;
|
import org.openhab.core.io.rest.RESTConstants;
|
||||||
import org.openhab.core.io.rest.RESTResource;
|
import org.openhab.core.io.rest.RESTResource;
|
||||||
|
import org.openhab.core.io.rest.core.discovery.DiscoveryInfoDTO;
|
||||||
|
import org.osgi.framework.Bundle;
|
||||||
|
import org.osgi.framework.FrameworkUtil;
|
||||||
import org.osgi.service.component.annotations.Activate;
|
import org.osgi.service.component.annotations.Activate;
|
||||||
import org.osgi.service.component.annotations.Component;
|
import org.osgi.service.component.annotations.Component;
|
||||||
import org.osgi.service.component.annotations.Reference;
|
import org.osgi.service.component.annotations.Reference;
|
||||||
@ -62,6 +76,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
* @author Franck Dechavanne - Added DTOs to ApiResponses
|
* @author Franck Dechavanne - Added DTOs to ApiResponses
|
||||||
* @author Markus Rathgeb - Migrated to JAX-RS Whiteboard Specification
|
* @author Markus Rathgeb - Migrated to JAX-RS Whiteboard Specification
|
||||||
* @author Wouter Born - Migrated to OpenAPI annotations
|
* @author Wouter Born - Migrated to OpenAPI annotations
|
||||||
|
* @author Laurent Garnier - Added discovery with an optional input parameter
|
||||||
*/
|
*/
|
||||||
@Component(service = { RESTResource.class, DiscoveryResource.class })
|
@Component(service = { RESTResource.class, DiscoveryResource.class })
|
||||||
@JaxrsResource
|
@JaxrsResource
|
||||||
@ -81,10 +96,15 @@ public class DiscoveryResource implements RESTResource {
|
|||||||
private final Logger logger = LoggerFactory.getLogger(DiscoveryResource.class);
|
private final Logger logger = LoggerFactory.getLogger(DiscoveryResource.class);
|
||||||
|
|
||||||
private final DiscoveryServiceRegistry discoveryServiceRegistry;
|
private final DiscoveryServiceRegistry discoveryServiceRegistry;
|
||||||
|
private final LocaleService localeService;
|
||||||
|
private final TranslationProvider i18nProvider;
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public DiscoveryResource(final @Reference DiscoveryServiceRegistry discoveryServiceRegistry) {
|
public DiscoveryResource(final @Reference DiscoveryServiceRegistry discoveryServiceRegistry,
|
||||||
|
final @Reference TranslationProvider translationProvider, final @Reference LocaleService localeService) {
|
||||||
this.discoveryServiceRegistry = discoveryServiceRegistry;
|
this.discoveryServiceRegistry = discoveryServiceRegistry;
|
||||||
|
this.i18nProvider = translationProvider;
|
||||||
|
this.localeService = localeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@ -96,13 +116,59 @@ public class DiscoveryResource implements RESTResource {
|
|||||||
return Response.ok(new LinkedHashSet<>(supportedBindings)).build();
|
return Response.ok(new LinkedHashSet<>(supportedBindings)).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/bindings/{bindingId}/info")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Operation(operationId = "getDiscoveryServicesInfo", summary = "Gets information about the discovery services for a binding.", responses = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DiscoveryInfoDTO.class))),
|
||||||
|
@ApiResponse(responseCode = "404", description = "Discovery service not found") })
|
||||||
|
public Response getDiscoveryServicesInfo(
|
||||||
|
@PathParam("bindingId") @Parameter(description = "binding Id") final String bindingId,
|
||||||
|
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @Parameter(description = "language") @Nullable String language) {
|
||||||
|
final Locale locale = localeService.getLocale(language);
|
||||||
|
String label = null;
|
||||||
|
String description = null;
|
||||||
|
boolean supported = false;
|
||||||
|
Set<DiscoveryService> discoveryServices = discoveryServiceRegistry.getDiscoveryServices(bindingId);
|
||||||
|
|
||||||
|
if (discoveryServices.isEmpty()) {
|
||||||
|
return JSONResponse.createResponse(Status.NOT_FOUND, null,
|
||||||
|
"No discovery service found for binding " + bindingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryService discoveryService : discoveryServices) {
|
||||||
|
if (discoveryService.isScanInputSupported()) {
|
||||||
|
Bundle bundle = FrameworkUtil.getBundle(discoveryService.getClass());
|
||||||
|
label = discoveryService.getScanInputLabel();
|
||||||
|
if (label != null) {
|
||||||
|
label = i18nProvider.getText(bundle, I18nUtil.stripConstant(label), label, locale);
|
||||||
|
}
|
||||||
|
description = discoveryService.getScanInputDescription();
|
||||||
|
if (description != null) {
|
||||||
|
description = i18nProvider.getText(bundle, I18nUtil.stripConstant(description), description,
|
||||||
|
locale);
|
||||||
|
}
|
||||||
|
supported = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response.ok(new DiscoveryInfoDTO(supported, label, description)).build();
|
||||||
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("/bindings/{bindingId}/scan")
|
@Path("/bindings/{bindingId}/scan")
|
||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
@Operation(operationId = "scan", summary = "Starts asynchronous discovery process for a binding and returns the timeout in seconds of the discovery operation.", responses = {
|
@Operation(operationId = "scan", summary = "Starts asynchronous discovery process for a binding and returns the timeout in seconds of the discovery operation.", responses = {
|
||||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = Integer.class))) })
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = Integer.class))),
|
||||||
public Response scan(@PathParam("bindingId") @Parameter(description = "bindingId") final String bindingId) {
|
@ApiResponse(responseCode = "404", description = "Discovery service not found") })
|
||||||
discoveryServiceRegistry.startScan(bindingId, new ScanListener() {
|
public Response scan(@PathParam("bindingId") @Parameter(description = "binding Id") final String bindingId,
|
||||||
|
@QueryParam("input") @Parameter(description = "input parameter to start the discovery") @Nullable String input) {
|
||||||
|
if (discoveryServiceRegistry.getDiscoveryServices(bindingId).isEmpty()) {
|
||||||
|
return JSONResponse.createResponse(Status.NOT_FOUND, null,
|
||||||
|
"No discovery service found for binding " + bindingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveryServiceRegistry.startScan(bindingId, input, new ScanListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onErrorOccurred(@Nullable Exception exception) {
|
public void onErrorOccurred(@Nullable Exception exception) {
|
||||||
logger.error("Error occurred while scanning for binding '{}'", bindingId, exception);
|
logger.error("Error occurred while scanning for binding '{}'", bindingId, exception);
|
||||||
|
@ -160,17 +160,19 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartScanNonExisting() {
|
public void testStartScanNonExisting() {
|
||||||
assertFalse(discoveryServiceRegistry.startScan(new ThingTypeUID("bindingId", "thingType"), null));
|
assertFalse(discoveryServiceRegistry.startScan(new ThingTypeUID("bindingId", "thingType"), null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartScanExisting() {
|
public void testStartScanExisting() {
|
||||||
assertTrue(discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null));
|
assertTrue(
|
||||||
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testScanFaulty() {
|
public void testScanFaulty() {
|
||||||
assertFalse(discoveryServiceRegistry.startScan(new ThingTypeUID(FAULTY_BINDING_ID, FAULTY_THING_TYPE), null));
|
assertFalse(
|
||||||
|
discoveryServiceRegistry.startScan(new ThingTypeUID(FAULTY_BINDING_ID, FAULTY_THING_TYPE), null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -182,7 +184,7 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
public void testAbortScanKnown() {
|
public void testAbortScanKnown() {
|
||||||
ScanListener mockScanListener = mock(ScanListener.class);
|
ScanListener mockScanListener = mock(ScanListener.class);
|
||||||
|
|
||||||
assertTrue(discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1),
|
assertTrue(discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
mockScanListener));
|
mockScanListener));
|
||||||
assertTrue(discoveryServiceRegistry.abortScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1)));
|
assertTrue(discoveryServiceRegistry.abortScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1)));
|
||||||
|
|
||||||
@ -195,7 +197,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
ScanListener mockScanListener = mock(ScanListener.class);
|
ScanListener mockScanListener = mock(ScanListener.class);
|
||||||
|
|
||||||
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
|
mockScanListener);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener, times(1)).onFinished());
|
||||||
verify(discoveryListenerMock, times(1)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(1)).thingDiscovered(any(), any());
|
||||||
@ -221,8 +224,10 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
ScanListener mockScanListener2 = mock(ScanListener.class);
|
ScanListener mockScanListener2 = mock(ScanListener.class);
|
||||||
|
|
||||||
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_2, ANY_THING_TYPE_2), mockScanListener2);
|
mockScanListener1);
|
||||||
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_2, ANY_THING_TYPE_2), null,
|
||||||
|
mockScanListener2);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
||||||
waitForAssert(() -> verify(mockScanListener2, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener2, times(1)).onFinished());
|
||||||
@ -234,7 +239,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
assertThat(inbox.getAll().size(), is(2));
|
assertThat(inbox.getAll().size(), is(2));
|
||||||
|
|
||||||
// start discovery again
|
// start discovery again
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
|
mockScanListener1);
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(2)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(2)).onFinished());
|
||||||
verify(discoveryListenerMock, times(3)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(3)).thingDiscovered(any(), any());
|
||||||
|
|
||||||
@ -250,7 +256,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
ScanListener mockScanListener1 = mock(ScanListener.class);
|
ScanListener mockScanListener1 = mock(ScanListener.class);
|
||||||
|
|
||||||
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
|
mockScanListener1);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
||||||
verify(discoveryListenerMock, times(1)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(1)).thingDiscovered(any(), any());
|
||||||
@ -264,7 +271,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
anotherDiscoveryServiceMockForBinding1, null));
|
anotherDiscoveryServiceMockForBinding1, null));
|
||||||
|
|
||||||
// start discovery again
|
// start discovery again
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
|
mockScanListener1);
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(2)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(2)).onFinished());
|
||||||
verify(discoveryListenerMock, times(3)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(3)).thingDiscovered(any(), any());
|
||||||
|
|
||||||
@ -288,7 +296,7 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
ScanListener mockScanListener1 = mock(ScanListener.class);
|
ScanListener mockScanListener1 = mock(ScanListener.class);
|
||||||
|
|
||||||
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.startScan(ANY_BINDING_ID_3_ANY_THING_TYPE_3_UID, mockScanListener1);
|
discoveryServiceRegistry.startScan(ANY_BINDING_ID_3_ANY_THING_TYPE_3_UID, null, mockScanListener1);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
||||||
verify(discoveryListenerMock, times(2)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(2)).thingDiscovered(any(), any());
|
||||||
@ -311,7 +319,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
assertThat(inbox.getAll().size(), is(2));
|
assertThat(inbox.getAll().size(), is(2));
|
||||||
|
|
||||||
// start discovery again
|
// start discovery again
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_3, ANY_THING_TYPE_3), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_3, ANY_THING_TYPE_3), null,
|
||||||
|
mockScanListener1);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
||||||
verify(discoveryListenerMock, times(4)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(4)).thingDiscovered(any(), any());
|
||||||
@ -343,7 +352,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
ScanListener mockScanListener1 = mock(ScanListener.class);
|
ScanListener mockScanListener1 = mock(ScanListener.class);
|
||||||
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.removeDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.removeDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
|
mockScanListener1);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
||||||
verifyNoMoreInteractions(discoveryListenerMock);
|
verifyNoMoreInteractions(discoveryListenerMock);
|
||||||
@ -357,7 +367,8 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
serviceRegs.add(
|
serviceRegs.add(
|
||||||
bundleContext.registerService(DiscoveryService.class.getName(), anotherDiscoveryServiceMock, null));
|
bundleContext.registerService(DiscoveryService.class.getName(), anotherDiscoveryServiceMock, null));
|
||||||
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
|
||||||
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), mockScanListener1);
|
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1), null,
|
||||||
|
mockScanListener1);
|
||||||
|
|
||||||
waitForAssert(mockScanListener1::onFinished);
|
waitForAssert(mockScanListener1::onFinished);
|
||||||
verify(discoveryListenerMock, times(2)).thingDiscovered(any(), any());
|
verify(discoveryListenerMock, times(2)).thingDiscovered(any(), any());
|
||||||
@ -366,7 +377,7 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testStartScanBindingId() {
|
public void testStartScanBindingId() {
|
||||||
ScanListener mockScanListener1 = mock(ScanListener.class);
|
ScanListener mockScanListener1 = mock(ScanListener.class);
|
||||||
discoveryServiceRegistry.startScan(ANY_BINDING_ID_1, mockScanListener1);
|
discoveryServiceRegistry.startScan(ANY_BINDING_ID_1, null, mockScanListener1);
|
||||||
|
|
||||||
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user