]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hueemulation] Replace Jersey dependency with JAX-RS Whiteboard (#8611)
authorWouter Born <github@maindrain.net>
Wed, 30 Sep 2020 01:53:43 +0000 (03:53 +0200)
committerGitHub <noreply@github.com>
Wed, 30 Sep 2020 01:53:43 +0000 (18:53 -0700)
Fixes #7647

Signed-off-by: Wouter Born <github@maindrain.net>
29 files changed:
bundles/org.openhab.io.hueemulation/pom.xml
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/ConfigStore.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/HueEmulationService.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/HueAuthorizedConfig.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/HueStateBulb.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/HueStateColorBulb.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/changerequest/HueStateChange.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/ConfigurationAccess.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroups.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Rules.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Scenes.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Schedules.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Sensors.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/StatusResource.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/UserManagement.java
bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/UpnpServer.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/CommonSetup.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ItemUIDtoHueIDMappingTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/RulesTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SceneTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ScheduleTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SensorTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/UsersAndConfigTests.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/mocks/ConfigStoreWithoutMetadata.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/mocks/DummyRuleRegistry.java
bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/upnp/UpnpTests.java
bundles/pom.xml
features/openhab-addons/pom.xml

index 1f50f23a677e5566ec9d649b05fc8c6fc426f066..0d1f77bda5d518e4bc74f14680f9ad7dee44c4dd 100644 (file)
 
   <name>openHAB Add-ons :: Bundles :: IO :: Hue Emulation Service</name>
 
-  <properties>
-    <bnd.importpackage>org.glassfish.jersey.*;resolution:="optional"</bnd.importpackage>
-  </properties>
-
   <dependencies>
     <!-- https://mvnrepository.com/artifact/org.glassfish.grizzly/grizzly-http-server -->
     <dependency>
index a10e7f79934d648f2107cdb8ab75e3d1ba754483..c084eb9d07003446e2c68d990978075b41eb4f97 100644 (file)
@@ -71,8 +71,7 @@ import com.google.gson.GsonBuilder;
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { ConfigStore.class }, configurationPid = {
-        HueEmulationService.CONFIG_PID }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = ConfigStore.class, configurationPid = HueEmulationService.CONFIG_PID)
 @ConfigurableService(category = "io", label = "Hue Emulation", description_uri = "io:hueemulation")
 @NonNullByDefault
 public class ConfigStore {
index 368428deac64084add9870acc6b7fb8cc6b3f199..17773a2520f4552d4a95273558cbc8ec609bc2dc 100644 (file)
@@ -14,9 +14,8 @@ package org.openhab.io.hueemulation.internal;
 
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.Set;
 
-import javax.servlet.ServletException;
-import javax.ws.rs.ApplicationPath;
 import javax.ws.rs.HttpMethod;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.ContainerRequestFilter;
@@ -28,10 +27,6 @@ import javax.ws.rs.core.Application;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.http.HttpHeader;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.server.ServerProperties;
-import org.glassfish.jersey.servlet.ServletContainer;
-import org.glassfish.jersey.servlet.ServletProperties;
 import org.openhab.io.hueemulation.internal.rest.ConfigurationAccess;
 import org.openhab.io.hueemulation.internal.rest.LightsAndGroups;
 import org.openhab.io.hueemulation.internal.rest.Rules;
@@ -42,6 +37,7 @@ import org.openhab.io.hueemulation.internal.rest.StatusResource;
 import org.openhab.io.hueemulation.internal.rest.UserManagement;
 import org.openhab.io.hueemulation.internal.upnp.UpnpServer;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -54,8 +50,8 @@ import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventHandler;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.http.NamespaceException;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -75,17 +71,12 @@ import org.slf4j.LoggerFactory;
  * @author David Graeff - Initial Contribution
  */
 @NonNullByDefault
-@Component(immediate = true, service = { HueEmulationService.class }, property = {
-        "com.eclipsesource.jaxrs.publish=false" })
+@Component(immediate = true, service = HueEmulationService.class)
 public class HueEmulationService implements EventHandler {
 
     public static final String CONFIG_PID = "org.openhab.hueemulation";
     public static final String RESTAPI_PATH = "/api";
-
-    @ApplicationPath(RESTAPI_PATH)
-    public static class JerseyApplication extends Application {
-
-    }
+    public static final String REST_APP_NAME = "HueEmulation";
 
     @PreMatching
     public class RequestInterceptor implements ContainerRequestFilter {
@@ -117,6 +108,34 @@ public class HueEmulationService implements EventHandler {
     }
 
     private final ContainerRequestFilter requestCleaner = new RequestInterceptor();
+
+    /**
+     * The Jax-RS application that starts up all REST activities.
+     * It registers itself as a Jax-RS Whiteboard service and all Jax-RS resources that are targeting REST_APP_NAME will
+     * start up.
+     */
+    @JaxrsName(REST_APP_NAME)
+    private class RESTapplication extends Application {
+        private String root;
+
+        RESTapplication(String root) {
+            this.root = root;
+        }
+
+        @NonNullByDefault({})
+        @Override
+        public Set<Object> getSingletons() {
+            return Set.of(userManagement, configurationAccess, lightItems, sensors, scenes, schedules, rules,
+                    statusResource, accessInterceptor);
+        }
+
+        Dictionary<String, String> serviceProperties() {
+            Dictionary<String, String> dict = new Hashtable<>();
+            dict.put(JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE, root);
+            return dict;
+        }
+    }
+
     private final Logger logger = LoggerFactory.getLogger(HueEmulationService.class);
     private final LogAccessInterceptor accessInterceptor = new LogAccessInterceptor();
 
@@ -144,9 +163,8 @@ public class HueEmulationService implements EventHandler {
     @Reference
     protected @NonNullByDefault({}) StatusResource statusResource;
 
-    @Reference
-    protected @NonNullByDefault({}) HttpService httpService;
-    private @NonNullByDefault({}) ServiceRegistration<?> eventHandler;
+    private @Nullable ServiceRegistration<?> eventHandler;
+    private @Nullable ServiceRegistration<Application> restService;
 
     @Activate
     protected void activate(BundleContext bc) {
@@ -165,15 +183,11 @@ public class HueEmulationService implements EventHandler {
 
     @Deactivate
     protected void deactivate() {
-        try {
-            if (eventHandler != null) {
-                eventHandler.unregister();
-            }
-        } catch (IllegalStateException ignore) {
-        }
-        try {
-            httpService.unregister(RESTAPI_PATH);
-        } catch (IllegalArgumentException ignore) {
+        unregisterEventHandler();
+
+        ServiceRegistration<Application> localRestService = restService;
+        if (localRestService != null) {
+            localRestService.unregister();
         }
     }
 
@@ -185,39 +199,26 @@ public class HueEmulationService implements EventHandler {
      */
     @Override
     public void handleEvent(@Nullable Event event) {
-        try { // Only receive this event once
-            eventHandler.unregister();
-            eventHandler = null;
-        } catch (IllegalStateException ignore) {
+        unregisterEventHandler();
+
+        ServiceRegistration<Application> localRestService = restService;
+        if (localRestService == null) {
+            RESTapplication app = new RESTapplication(RESTAPI_PATH);
+            BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+            restService = context.registerService(Application.class, app, app.serviceProperties());
+            logger.info("Hue Emulation service available under {}", RESTAPI_PATH);
         }
+    }
 
-        ResourceConfig resourceConfig = ResourceConfig.forApplicationClass(JerseyApplication.class);
-        resourceConfig.property(ServerProperties.APPLICATION_NAME, "HueEmulation");
-        // don't look for implementations described by META-INF/services/*
-        resourceConfig.property(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
-        // disable auto discovery on server, as it's handled via OSGI
-        resourceConfig.property(ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
-
-        resourceConfig.property(ServerProperties.PROCESSING_RESPONSE_ERRORS_ENABLED, true);
-
-        resourceConfig.registerInstances(userManagement, configurationAccess, lightItems, sensors, scenes, schedules,
-                rules, statusResource, accessInterceptor, requestCleaner);
-
-        try {
-            Hashtable<String, String> initParams = new Hashtable<>();
-            initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "false");
-            initParams.put(ServletProperties.PROVIDER_WEB_APP, "false");
-            httpService.registerServlet(RESTAPI_PATH, new ServletContainer(resourceConfig), initParams, null);
-            UpnpServer localDiscovery = discovery;
-            if (localDiscovery == null) {
-                logger.warn("The UPnP Server service has not been started!");
-            } else if (!localDiscovery.upnpAnnouncementThreadRunning()) {
-                localDiscovery.handleEvent(null);
+    private void unregisterEventHandler() {
+        ServiceRegistration<?> localEventHandler = eventHandler;
+        if (localEventHandler != null) {
+            try {
+                localEventHandler.unregister();
+                eventHandler = null;
+            } catch (IllegalStateException e) {
+                logger.debug("EventHandler already unregistered", e);
             }
-            statusResource.startUpnpSelfTest();
-            logger.info("Hue Emulation service available under {}", RESTAPI_PATH);
-        } catch (ServletException | NamespaceException e) {
-            logger.warn("Could not start Hue Emulation service: {}", e.getMessage(), e);
         }
     }
 }
index 2d25a16b18ee3973093091912e4a2188feb393f3..b5dfa947cf4a12a5a2107d503430af9924ae8216 100644 (file)
@@ -79,7 +79,7 @@ public class HueAuthorizedConfig extends HueUnauthorizedConfig {
 
     /**
      * Return a json serializer that behaves like the default one, but updates the UTC and localtime fields
-     * before each serializion.
+     * before each serialization.
      */
     @NonNullByDefault({})
     public static class Serializer implements JsonSerializer<HueAuthorizedConfig> {
index 81a81f7d0515a85a449b7ec2f8784c13849e2b8e..5c1a28adfddd5afca5acf09e104bc5753535c987 100644 (file)
@@ -24,11 +24,11 @@ import org.openhab.core.library.types.PercentType;
 public class HueStateBulb extends HueStatePlug {
     // https://github.com/openhab/openhab-addons/issues/2881
     // Apparently the maximum brightness is 254
-    public static int MAX_BRI = 254;
+    public static final int MAX_BRI = 254;
     public int bri = 0;
 
     /** white color temperature, 154 (cold) - 500 (warm) */
-    public static int MAX_CT = 500;
+    public static final int MAX_CT = 500;
     public int ct = 500;
 
     protected HueStateBulb() {
index a908799daaedb3381426ef2989d718ab3f9827b8..68957c7d02993fe9b0f1fe2cb23b782a2dc3a01e 100644 (file)
@@ -25,9 +25,9 @@ import org.openhab.core.library.types.PercentType;
  *
  */
 public class HueStateColorBulb extends HueStateBulb {
-    public static int MAX_HUE = 65535; // For extended color light bulbs
+    public static final int MAX_HUE = 65535; // For extended color light bulbs
     public int hue = 0;
-    public static int MAX_SAT = 254;
+    public static final int MAX_SAT = 254;
     public int sat = 0;
 
     // color as array of xy-coordinates
index 6a4330a8e545f241b2c89669c2b0a9aac4be50db..899089b5b4b5c29a05d4893c826072920d609d0e 100644 (file)
@@ -15,7 +15,7 @@ package org.openhab.io.hueemulation.internal.dto.changerequest;
 import java.util.List;
 
 /**
- * A POST message on a light entpoint will contain this change message body.
+ * A POST message on a light endpoint will contain this change message body.
  * Not all fields will be set and always need to be checked.
  *
  * @author David Graeff - Initial contribution
index c815b4c0dbd8857a4c8d566bd5169110d820addc..d1782c2e16c35259746c7364d765a5e103dd1452 100644 (file)
@@ -27,6 +27,7 @@ import javax.ws.rs.core.UriInfo;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.dto.HueUnauthorizedConfig;
 import org.openhab.io.hueemulation.internal.dto.changerequest.HueChangeRequest;
@@ -35,19 +36,22 @@ import org.openhab.io.hueemulation.internal.dto.response.HueResponse.HueErrorMes
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 
 import com.google.gson.reflect.TypeToken;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = {
-        ConfigurationAccess.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = ConfigurationAccess.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -62,8 +66,8 @@ public class ConfigurationAccess {
     @GET
     @Path("config")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return the reduced configuration")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return the reduced configuration", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response getReducedConfigApi() {
         return Response.ok(cs.gson.toJson(cs.ds.config, new TypeToken<HueUnauthorizedConfig>() {
         }.getType())).build();
@@ -72,10 +76,10 @@ public class ConfigurationAccess {
     @GET
     @Path("{username}")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return the full data store")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return the full data store", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response getAllApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -85,10 +89,10 @@ public class ConfigurationAccess {
     @GET
     @Path("{username}/config")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return the configuration")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return the configuration", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response getFullConfigApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -98,10 +102,10 @@ public class ConfigurationAccess {
     @PUT
     @Path("{username}/config")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return the reduced configuration")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return the reduced configuration", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response putFullConfigApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username, String body) {
+            @PathParam("username") @Parameter(description = "username") String username, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index b321a175f71d01ed36b91cbabe663eb8e88a577f..2e28f852d9143ee59176547f0a55674651bf7027 100644 (file)
@@ -43,6 +43,7 @@ import org.openhab.core.library.CoreItemFactory;
 import org.openhab.core.types.Command;
 import org.openhab.io.hueemulation.internal.ConfigStore;
 import org.openhab.io.hueemulation.internal.DeviceType;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.StateUtils;
 import org.openhab.io.hueemulation.internal.dto.HueGroupEntry;
@@ -57,15 +58,17 @@ import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.gson.reflect.TypeToken;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * Listens to the ItemRegistry for items that fulfill one of these criteria:
@@ -93,7 +96,9 @@ import io.swagger.annotations.ApiResponses;
  * @author David Graeff - Initial contribution
  * @author Florian Schmidt - Removed base type restriction from Group items
  */
-@Component(immediate = false, service = { LightsAndGroups.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = LightsAndGroups.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -241,10 +246,9 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/lights")
-    @ApiOperation(value = "Return all lights")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all lights", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getAllLightsApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -253,10 +257,10 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/lights/new")
-    @ApiOperation(value = "Return new lights since last scan. Returns an empty list for openHAB as we do not cache that information.")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return new lights since last scan. Returns an empty list for openHAB as we do not cache that information.", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response getNewLights(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -265,10 +269,10 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
 
     @POST
     @Path("{username}/lights")
-    @ApiOperation(value = "Starts a new scan for compatible items. This is usually not necessary, because we are observing the item registry.")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Starts a new scan for compatible items. This is usually not necessary, because we are observing the item registry.", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response postNewLights(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -277,11 +281,10 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/lights/{id}")
-    @ApiOperation(value = "Return a light")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a light", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getLightApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "light id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "light id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -291,12 +294,12 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @DELETE
     @Path("{username}/lights/{id}")
-    @ApiOperation(value = "Deletes the item that is represented by this id")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The item got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes the item that is represented by this id", responses = {
+            @ApiResponse(responseCode = "200", description = "The item got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeLightAPI(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -316,11 +319,10 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @PUT
     @Path("{username}/lights/{id}")
-    @ApiOperation(value = "Rename a light")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Rename a light", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response renameLightApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "light id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "light id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -345,11 +347,10 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @PUT
     @Path("{username}/lights/{id}/state")
-    @ApiOperation(value = "Set light state")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Set light state", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response setLightStateApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "light id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "light id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -391,11 +392,11 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @PUT
     @Path("{username}/groups/{id}/action")
-    @ApiOperation(value = "Initiate group action")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Initiate group action", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response setGroupActionApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "group id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "group id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -436,10 +437,9 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/groups")
-    @ApiOperation(value = "Return all groups")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all groups", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getAllGroupsApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -448,11 +448,10 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/groups/{id}")
-    @ApiOperation(value = "Return a group")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a group", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getGroupApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "group id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "group id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -462,10 +461,9 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @POST
     @Path("{username}/groups")
-    @ApiOperation(value = "Create a new group")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Create a new group", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response postNewGroup(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username, String body) {
+            @PathParam("username") @Parameter(description = "username") String username, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -506,12 +504,12 @@ public class LightsAndGroups implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @DELETE
     @Path("{username}/groups/{id}")
-    @ApiOperation(value = "Deletes the item that is represented by this id")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The item got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes the item that is represented by this id", responses = {
+            @ApiResponse(responseCode = "200", description = "The item got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeGroupAPI(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index 67039626debc94f592500df8b7a7da84216d2ed2..37ee3949608392fdafc8a82e897c0beefdc099a6 100644 (file)
@@ -49,6 +49,7 @@ import org.openhab.core.config.core.Configuration;
 import org.openhab.core.items.Item;
 import org.openhab.core.items.ItemRegistry;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.RuleUtils;
 import org.openhab.io.hueemulation.internal.dto.HueRuleEntry;
@@ -59,18 +60,22 @@ import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * Handles Hue rules via the automation subsystem and the corresponding REST interface
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { Rules.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = Rules.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -234,10 +239,9 @@ public class Rules implements RegistryChangeListener<Rule> {
     @GET
     @Path("{username}/rules")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return all rules")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all rules", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getRulesApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -246,11 +250,10 @@ public class Rules implements RegistryChangeListener<Rule> {
 
     @GET
     @Path("{username}/rules/{id}")
-    @ApiOperation(value = "Return a rule")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a rule", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getRuleApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "rule id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "rule id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -259,12 +262,12 @@ public class Rules implements RegistryChangeListener<Rule> {
 
     @DELETE
     @Path("{username}/rules/{id}")
-    @ApiOperation(value = "Deletes a rule")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The user got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes a rule", responses = {
+            @ApiResponse(responseCode = "200", description = "The user got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeRuleApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "Rule to remove") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "Rule to remove") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -279,11 +282,10 @@ public class Rules implements RegistryChangeListener<Rule> {
 
     @PUT
     @Path("{username}/rules/{id}")
-    @ApiOperation(value = "Set rule attributes")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Set rule attributes", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response modifyRuleApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "rule id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "rule id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -334,10 +336,9 @@ public class Rules implements RegistryChangeListener<Rule> {
     @SuppressWarnings({ "null" })
     @POST
     @Path("{username}/rules")
-    @ApiOperation(value = "Create a new rule")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Create a new rule", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response postNewRule(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username, String body) {
+            @PathParam("username") @Parameter(description = "username") String username, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index 2f542ee852e9746c239c01b261a19a828b1a2d2a..16ae0d477c76c16311c9760ae626f7a98b79bcda 100644 (file)
@@ -49,6 +49,7 @@ import org.openhab.core.items.ItemRegistry;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.State;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.StateUtils;
 import org.openhab.io.hueemulation.internal.automation.dto.ItemCommandActionConfig;
@@ -63,20 +64,24 @@ import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * Handles Hue scenes via the automation subsystem and the corresponding REST interface
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { Scenes.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = Scenes.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -165,10 +170,9 @@ public class Scenes implements RegistryChangeListener<Rule> {
     @GET
     @Path("{username}/scenes")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return all scenes")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all scenes", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getScenesApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -178,11 +182,10 @@ public class Scenes implements RegistryChangeListener<Rule> {
     @SuppressWarnings({ "unused", "null" })
     @GET
     @Path("{username}/scenes/{id}")
-    @ApiOperation(value = "Return a scene")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a scene", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getSceneApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "scene id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "scene id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -208,12 +211,12 @@ public class Scenes implements RegistryChangeListener<Rule> {
 
     @DELETE
     @Path("{username}/scenes/{id}")
-    @ApiOperation(value = "Deletes a scene")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The user got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes a scene", responses = {
+            @ApiResponse(responseCode = "200", description = "The user got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeSceneApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "Scene to remove") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "Scene to remove") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -248,11 +251,10 @@ public class Scenes implements RegistryChangeListener<Rule> {
      */
     @PUT
     @Path("{username}/scenes/{id}")
-    @ApiOperation(value = "Set scene attributes")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Set scene attributes", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response modifySceneApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "scene id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "scene id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -317,10 +319,9 @@ public class Scenes implements RegistryChangeListener<Rule> {
     @SuppressWarnings({ "null" })
     @POST
     @Path("{username}/scenes")
-    @ApiOperation(value = "Create a new scene")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Create a new scene", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response postNewScene(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username, String body) {
+            @PathParam("username") @Parameter(description = "username") String username, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -372,12 +373,11 @@ public class Scenes implements RegistryChangeListener<Rule> {
 
     @PUT
     @Path("{username}/scenes/{id}/lightstates/{lightid}")
-    @ApiOperation(value = "Set scene attributes")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Set scene attributes", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response modifySceneLightStateApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "scene id") String id,
-            @PathParam("lightid") @ApiParam(value = "light id") String lightid, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "scene id") String id,
+            @PathParam("lightid") @Parameter(description = "light id") String lightid, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index 0c9ad30eb5c5b649f6edfbfaa0c3918ea9017534..801e558389218aa9b152889a221fe4af38915800 100644 (file)
@@ -44,6 +44,7 @@ import org.openhab.core.automation.util.RuleBuilder;
 import org.openhab.core.common.registry.RegistryChangeListener;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.RuleUtils;
 import org.openhab.io.hueemulation.internal.dto.HueDataStore;
@@ -56,13 +57,15 @@ import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * Enables the schedule part of the Hue REST API. Uses automation rules with GenericCronTrigger, TimerTrigger and
@@ -74,7 +77,9 @@ import io.swagger.annotations.ApiResponses;
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { Schedules.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = Schedules.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -228,10 +233,9 @@ public class Schedules implements RegistryChangeListener<Rule> {
     @GET
     @Path("{username}/schedules")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Return all schedules")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all schedules", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getSchedulesApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -240,11 +244,10 @@ public class Schedules implements RegistryChangeListener<Rule> {
 
     @GET
     @Path("{username}/schedules/{id}")
-    @ApiOperation(value = "Return a schedule")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a schedule", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getScheduleApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "schedule id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "schedule id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -253,12 +256,12 @@ public class Schedules implements RegistryChangeListener<Rule> {
 
     @DELETE
     @Path("{username}/schedules/{id}")
-    @ApiOperation(value = "Deletes a schedule")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The user got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes a schedule", responses = {
+            @ApiResponse(responseCode = "200", description = "The user got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeScheduleApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "Schedule to remove") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "Schedule to remove") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -273,11 +276,11 @@ public class Schedules implements RegistryChangeListener<Rule> {
 
     @PUT
     @Path("{username}/schedules/{id}")
-    @ApiOperation(value = "Set schedule attributes")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Set schedule attributes", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response modifyScheduleApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "schedule id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "schedule id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -311,10 +314,10 @@ public class Schedules implements RegistryChangeListener<Rule> {
     @SuppressWarnings({ "null" })
     @POST
     @Path("{username}/schedules")
-    @ApiOperation(value = "Create a new schedule")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Create a new schedule", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response postNewSchedule(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username, String body) {
+            @PathParam("username") @Parameter(description = "username") String username, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index c438fc650ace272003df0c33fe5f87b49dd9434c..f8fd1f00130cfc019b75ab2b758a153e5c3a179b 100644 (file)
@@ -36,6 +36,7 @@ import org.openhab.core.items.Item;
 import org.openhab.core.items.ItemRegistry;
 import org.openhab.core.library.CoreItemFactory;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.dto.HueNewLights;
 import org.openhab.io.hueemulation.internal.dto.HueSensorEntry;
@@ -45,13 +46,15 @@ import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * Listens to the ItemRegistry and add all DecimalType, OnOffType, ContactType, DimmerType items
@@ -59,7 +62,9 @@ import io.swagger.annotations.ApiResponses;
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { Sensors.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = Sensors.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -144,10 +149,9 @@ public class Sensors implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/sensors")
-    @ApiOperation(value = "Return all sensors")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all sensors", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getAllSensorsApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -156,10 +160,10 @@ public class Sensors implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/sensors/new")
-    @ApiOperation(value = "Return new sensors since last scan. Returns an empty list for openHAB as we do not cache that information.")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return new sensors since last scan. Returns an empty list for openHAB as we do not cache that information.", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response getNewSensors(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -168,10 +172,10 @@ public class Sensors implements RegistryChangeListener<Item> {
 
     @POST
     @Path("{username}/sensors")
-    @ApiOperation(value = "Starts a new scan for compatible items. This is usually not necessary, because we are observing the item registry.")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Starts a new scan for compatible items. This is usually not necessary, because we are observing the item registry.", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response postNewLights(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -180,11 +184,10 @@ public class Sensors implements RegistryChangeListener<Item> {
 
     @GET
     @Path("{username}/sensors/{id}")
-    @ApiOperation(value = "Return a sensor")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a sensor", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getSensorApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "sensor id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "sensor id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -194,11 +197,11 @@ public class Sensors implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @GET
     @Path("{username}/sensors/{id}/config")
-    @ApiOperation(value = "Return a sensor config. Always empty")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a sensor config. Always empty", responses = {
+            @ApiResponse(responseCode = "200", description = "OK") })
     public Response getSensorConfigApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "sensor id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "sensor id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -214,12 +217,12 @@ public class Sensors implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @DELETE
     @Path("{username}/sensors/{id}")
-    @ApiOperation(value = "Deletes the sensor that is represented by this id")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The item got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes the sensor that is represented by this id", responses = {
+            @ApiResponse(responseCode = "200", description = "The item got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeSensorAPI(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "id") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "id") String id) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -239,11 +242,10 @@ public class Sensors implements RegistryChangeListener<Item> {
     @SuppressWarnings({ "null", "unused" })
     @PUT
     @Path("{username}/sensors/{id}")
-    @ApiOperation(value = "Rename a sensor")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Rename a sensor", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response renameLightApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "light id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "light id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -267,11 +269,10 @@ public class Sensors implements RegistryChangeListener<Item> {
 
     @PUT
     @Path("{username}/sensors/{id}/state")
-    @ApiOperation(value = "Set sensor state")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Set sensor state", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response setSensorStateApi(@Context UriInfo uri, //
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "sensor id") String id, String body) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "sensor id") String id, String body) {
         if (!userManagement.authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index 4450a1dd632f204cbb562a839f4bb60528a1618d..c1891c55b3662e57116e249b4d696ad07a67cb56 100644 (file)
@@ -33,11 +33,15 @@ import org.jupnp.model.meta.RemoteDevice;
 import org.jupnp.registry.Registry;
 import org.jupnp.registry.RegistryListener;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.upnp.UpnpServer;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,9 +53,11 @@ import org.slf4j.LoggerFactory;
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { StatusResource.class }, property = "com.eclipsesource.jaxrs.publish=false")
-@Path("")
+@Component(immediate = false, service = StatusResource.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
+@Path("")
 public class StatusResource implements RegistryListener {
     @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY)
     protected @Nullable UpnpServer discovery;
index c2c3750bd10d6073308b4afbf9b3011cea225d3b..60e129abaacba40fb06e4bdac8b30c672adbc6d2 100644 (file)
@@ -33,6 +33,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.core.common.registry.DefaultAbstractManagedProvider;
 import org.openhab.core.storage.StorageService;
 import org.openhab.io.hueemulation.internal.ConfigStore;
+import org.openhab.io.hueemulation.internal.HueEmulationService;
 import org.openhab.io.hueemulation.internal.NetworkUtils;
 import org.openhab.io.hueemulation.internal.dto.HueUserAuth;
 import org.openhab.io.hueemulation.internal.dto.HueUserAuthWithSecrets;
@@ -42,15 +43,17 @@ import org.openhab.io.hueemulation.internal.dto.response.HueSuccessResponseCreat
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
+import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.gson.reflect.TypeToken;
 
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
 /**
  * Manages users of this emulated HUE bridge. Stores users in the frameworks storage backend.
@@ -64,7 +67,9 @@ import io.swagger.annotations.ApiResponses;
  *
  * @author David Graeff - Initial contribution
  */
-@Component(immediate = false, service = { UserManagement.class }, property = "com.eclipsesource.jaxrs.publish=false")
+@Component(immediate = false, service = UserManagement.class)
+@JaxrsResource
+@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + HueEmulationService.REST_APP_NAME + ")")
 @NonNullByDefault
 @Path("")
 @Produces(MediaType.APPLICATION_JSON)
@@ -147,9 +152,9 @@ public class UserManagement extends DefaultAbstractManagedProvider<HueUserAuthWi
     }
 
     @POST
-    @ApiOperation(value = "Create an API Key")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "API Key created"),
-            @ApiResponse(code = 403, message = "Link button not pressed") })
+    @Operation(summary = "Create an API Key", responses = {
+            @ApiResponse(responseCode = "200", description = "API Key created"),
+            @ApiResponse(responseCode = "403", description = "Link button not pressed") })
     public Response createNewUser(@Context UriInfo uri, String body) {
         if (!cs.ds.config.linkbutton) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.LINK_BUTTON_NOT_PRESSED,
@@ -175,11 +180,10 @@ public class UserManagement extends DefaultAbstractManagedProvider<HueUserAuthWi
 
     @GET
     @Path("{username}/config/whitelist/{userid}")
-    @ApiOperation(value = "Return a user")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return a user", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getUserApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("userid") @ApiParam(value = "User ID") String userid) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("userid") @Parameter(description = "User ID") String userid) {
         if (!authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -188,10 +192,9 @@ public class UserManagement extends DefaultAbstractManagedProvider<HueUserAuthWi
 
     @GET
     @Path("{username}/config/whitelist")
-    @ApiOperation(value = "Return all users")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
+    @Operation(summary = "Return all users", responses = { @ApiResponse(responseCode = "200", description = "OK") })
     public Response getAllUsersApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username) {
+            @PathParam("username") @Parameter(description = "username") String username) {
         if (!authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
@@ -200,12 +203,12 @@ public class UserManagement extends DefaultAbstractManagedProvider<HueUserAuthWi
 
     @DELETE
     @Path("{username}/config/whitelist/{id}")
-    @ApiOperation(value = "Deletes a user")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "The user got removed"),
-            @ApiResponse(code = 403, message = "Access denied") })
+    @Operation(summary = "Deletes a user", responses = {
+            @ApiResponse(responseCode = "200", description = "The user got removed"),
+            @ApiResponse(responseCode = "403", description = "Access denied") })
     public Response removeUserApi(@Context UriInfo uri,
-            @PathParam("username") @ApiParam(value = "username") String username,
-            @PathParam("id") @ApiParam(value = "User to remove") String id) {
+            @PathParam("username") @Parameter(description = "username") String username,
+            @PathParam("id") @Parameter(description = "User to remove") String id) {
         if (!authorizeUser(username)) {
             return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized");
         }
index 62dda2b0a81e1527fc5e2be50076fa8f2267c2c0..6ad3e5fc1823e4058b2c40882b207dd7e9fed212 100644 (file)
@@ -41,6 +41,7 @@ import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -55,8 +56,6 @@ import javax.ws.rs.core.Response;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
 import org.openhab.io.hueemulation.internal.ConfigStore;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -82,8 +81,7 @@ import org.slf4j.LoggerFactory;
 @NonNullByDefault
 @Component(immediate = false, // Don't start the upnp server on its own. Must be pulled in by HueEmulationService.
         configurationPolicy = ConfigurationPolicy.IGNORE, property = {
-                EventConstants.EVENT_TOPIC + "=" + ConfigStore.EVENT_ADDRESS_CHANGED,
-                "com.eclipsesource.jaxrs.publish=false" }, //
+                EventConstants.EVENT_TOPIC + "=" + ConfigStore.EVENT_ADDRESS_CHANGED }, //
         service = { UpnpServer.class, EventHandler.class })
 public class UpnpServer extends HttpServlet implements Consumer<HueEmulationConfigWithRuntime>, EventHandler {
     /**
@@ -121,6 +119,9 @@ public class UpnpServer extends HttpServlet implements Consumer<HueEmulationConf
     @Reference
     protected @NonNullByDefault({}) HttpService httpService;
 
+    @Reference
+    protected @NonNullByDefault({}) ClientBuilder clientBuilder;
+
     public boolean overwriteReadyToFalse = false;
 
     private HueEmulationConfigWithRuntime config;
@@ -242,11 +243,7 @@ public class UpnpServer extends HttpServlet implements Consumer<HueEmulationConf
         }
 
         selfTests.clear();
-
-        ClientConfig configuration = new ClientConfig();
-        configuration = configuration.property(ClientProperties.CONNECT_TIMEOUT, 1000);
-        configuration = configuration.property(ClientProperties.READ_TIMEOUT, 1000);
-        Client client = ClientBuilder.newClient(configuration);
+        Client client = clientBuilder.connectTimeout(1, TimeUnit.SECONDS).readTimeout(1, TimeUnit.SECONDS).build();
         Response response;
         String url = "";
         try {
index 761749291d8bf7820b8fd076091663b3d0a275c6..0ab183c4c0564436f4fc21fa93b9d6272947fd45 100644 (file)
@@ -34,12 +34,9 @@ import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
 import org.glassfish.jersey.logging.LoggingFeature;
 import org.glassfish.jersey.logging.LoggingFeature.Verbosity;
 import org.glassfish.jersey.server.ResourceConfig;
-import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
+import org.mockito.MockitoAnnotations;
 import org.openhab.core.events.EventPublisher;
 import org.openhab.core.items.MetadataRegistry;
 import org.openhab.core.net.NetworkAddressService;
@@ -61,15 +58,19 @@ import org.osgi.service.cm.ConfigurationAdmin;
  *
  * @author David Graeff - Initial contribution
  */
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.WARN)
 public class CommonSetup {
 
-    public UserManagement userManagement;
+    public String basePath;
+    public Client client;
+    public ConfigStore cs;
+    public HttpServer server;
 
-    public @Mock EventPublisher eventPublisher;
+    UserManagement userManagement;
 
-    public ConfigStore cs;
+    AutoCloseable mocksCloseable;
+
+    @Mock
+    EventPublisher eventPublisher;
 
     @Mock
     ConfigurationAdmin configAdmin;
@@ -101,11 +102,9 @@ public class CommonSetup {
         }
     };
 
-    public Client client;
-    public HttpServer server;
-    public String basePath;
-
     public CommonSetup(boolean withMetadata) throws IOException {
+        mocksCloseable = MockitoAnnotations.openMocks(this);
+
         when(configAdmin.getConfiguration(anyString())).thenReturn(configAdminConfig);
         when(configAdmin.getConfiguration(anyString(), any())).thenReturn(configAdminConfig);
         Dictionary<String, Object> mockProperties = new Hashtable<>();
@@ -154,12 +153,14 @@ public class CommonSetup {
         client = ClientBuilder.newClient();
     }
 
-    public void dispose() {
+    public void dispose() throws Exception {
         if (client != null) {
             client.close();
         }
         if (server != null) {
             server.shutdownNow();
         }
+
+        mocksCloseable.close();
     }
 }
index cc41b1909a2a989ed11648b102018441ad2db062..bfa5da42b7e7586f771eaddcc386ae2ee4f16115 100644 (file)
@@ -62,7 +62,7 @@ public class ItemUIDtoHueIDMappingTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         commonSetup.dispose();
     }
 
index c8a70e6a6a3dbf39dcfac1eca71eb768488275d8..fc61d536990e2832ab8549de4173209aac6752b6 100644 (file)
@@ -83,7 +83,7 @@ public class LightsAndGroupsTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         commonSetup.dispose();
     }
 
index 1dae91e749aa91b15fd8da880fb6c62ac022a4ad..0536831a0d6de5ba3e00fb14b5e619240077b128 100644 (file)
@@ -61,6 +61,7 @@ import com.google.gson.reflect.TypeToken;
  */
 @NonNullByDefault
 public class RulesTests {
+
     protected @NonNullByDefault({}) CommonSetup commonSetup;
     protected @NonNullByDefault({}) ConfigStore cs;
     protected @NonNullByDefault({}) ItemRegistry itemRegistry;
@@ -106,7 +107,7 @@ public class RulesTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         RuleUtils.random = new Random();
         commonSetup.dispose();
     }
index 68c223c46c44ccfe7d2123e048aa44905dca0dfb..17a94926083e077509bc067b13613f46427ceb99 100644 (file)
@@ -99,7 +99,7 @@ public class SceneTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         commonSetup.dispose();
     }
 
index bf809af33130fc33ddab824653058bd3e05ab027..86956130362f984c267b31c0adcfe7988222bea0 100644 (file)
@@ -99,7 +99,7 @@ public class ScheduleTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         RuleUtils.random = new Random();
         commonSetup.dispose();
     }
index 5c4a3b2c9eec6277a56dae8a0bc91de79bb42704..7ef24aa98f44287b56a4c33c9b2858e980269d9d 100644 (file)
@@ -86,7 +86,7 @@ public class SensorTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         commonSetup.dispose();
     }
 
index d8d711eddc63c8dd5d1be4235a83097565af474f..f129e2109bb13a341befb168067b5d9e1fc6d29e 100644 (file)
@@ -62,7 +62,7 @@ public class UsersAndConfigTests {
     }
 
     @AfterEach
-    public void tearDown() {
+    public void tearDown() throws Exception {
         commonSetup.dispose();
     }
 
index e7d877cb4a31853834e36c418c77b622178a7450..6abc57f1875d230c2ef4ab8f7f146e394fcec540 100644 (file)
@@ -14,7 +14,7 @@ package org.openhab.io.hueemulation.internal.rest.mocks;
 
 import java.util.concurrent.ScheduledExecutorService;
 
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.core.items.Item;
 import org.openhab.core.net.NetworkAddressService;
@@ -27,6 +27,7 @@ import org.osgi.service.cm.ConfigurationAdmin;
  *
  * @author David Graeff - Initial contribution
  */
+@NonNullByDefault
 public class ConfigStoreWithoutMetadata extends ConfigStore {
 
     public ConfigStoreWithoutMetadata(NetworkAddressService networkAddressService, ConfigurationAdmin configAdmin,
@@ -39,7 +40,7 @@ public class ConfigStoreWithoutMetadata extends ConfigStore {
     }
 
     @Override
-    public @NonNull String mapItemUIDtoHueID(@Nullable Item item) {
+    public String mapItemUIDtoHueID(@Nullable Item item) {
         if (item == null) {
             throw new IllegalArgumentException();
         }
index df2a893a41719a635dbb93125a22fe85263a417a..0afee55b4b9dd1418ade442e523a51041a3257b4 100644 (file)
@@ -44,7 +44,6 @@ public class DummyRuleRegistry implements RuleRegistry {
         return items.values();
     }
 
-    @NonNullByDefault({})
     @Override
     public Stream<Rule> stream() {
         return items.values().stream();
@@ -87,13 +86,11 @@ public class DummyRuleRegistry implements RuleRegistry {
         return put;
     }
 
-    @NonNullByDefault({})
     @Override
-    public Collection<Rule> getByTag(String tag) {
+    public Collection<Rule> getByTag(@Nullable String tag) {
         return Collections.emptyList();
     }
 
-    @NonNullByDefault({})
     @Override
     public Collection<Rule> getByTags(String... tags) {
         return Collections.emptyList();
index 2193f1f21aacdf903ea52f35f239865273935d5b..63da3f003fad0b303d9925adff5ca66d4d86ac21 100644 (file)
@@ -25,6 +25,7 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.core.Response;
 
 import org.glassfish.grizzly.osgi.httpservice.HttpServiceImpl;
@@ -81,6 +82,7 @@ public class UpnpTests {
             return null;
         }).when(executor).execute(ArgumentMatchers.any());
         subject = new UpnpServer(executor);
+        subject.clientBuilder = ClientBuilder.newBuilder();
         subject.httpService = httpServiceImpl;
         subject.cs = commonSetup.cs;
         subject.overwriteReadyToFalse = true;
@@ -94,7 +96,7 @@ public class UpnpTests {
     }
 
     @AfterAll
-    public static void tearDownHttp() {
+    public static void tearDownHttp() throws Exception {
         mainHttpHandler.unregisterAll();
         commonSetup.dispose();
     }
index 440974cc570401a00e2403cd5c8e54fbfe4aba90..84131e525de7aaee566821a3a83006eaccd41c01 100644 (file)
   <modules>
     <!-- io -->
     <module>org.openhab.io.homekit</module>
+    <module>org.openhab.io.hueemulation</module>
     <module>org.openhab.io.imperihome</module>
+    <module>org.openhab.io.mqttembeddedbroker</module>
     <module>org.openhab.io.neeo</module>
     <module>org.openhab.io.openhabcloud</module>
     <module>org.openhab.io.transport.modbus</module>
-    <module>org.openhab.io.mqttembeddedbroker</module>
     <!-- transformations -->
     <module>org.openhab.transform.bin2json</module>
     <module>org.openhab.transform.exec</module>
index bc6d0afd4559d55f76b256c3b94487a407093726..4f5e096bf3bb144115472f6c66a56eb8c5f1b58d 100644 (file)
@@ -52,7 +52,6 @@
 
                     <!-- temporarily exclude add-ons, which are still excluded from the build -->
                     <exclude name="**/org.openhab.binding.netatmo/**/feature.xml"/>
-                    <exclude name="**/org.openhab.io.hueemulation/**/feature.xml"/>
                   </fileset>
                   <filterchain>
                     <linecontainsRegExp>