diff --git a/bom/smarthomej-addons/pom.xml b/bom/smarthomej-addons/pom.xml
index e837e64c32..505650bdbd 100644
--- a/bom/smarthomej-addons/pom.xml
+++ b/bom/smarthomej-addons/pom.xml
@@ -31,11 +31,6 @@
org.smarthomej.binding.amazonechocontrol${project.version}
-
- org.smarthomej.addons.bundles
- org.smarthomej.binding.http
- ${project.version}
- org.smarthomej.addons.bundlesorg.smarthomej.binding.notificationsforfiretv
diff --git a/bundles/org.smarthomej.binding.http/NOTICE b/bundles/org.smarthomej.binding.http/NOTICE
deleted file mode 100644
index 68e64ecfc4..0000000000
--- a/bundles/org.smarthomej.binding.http/NOTICE
+++ /dev/null
@@ -1,15 +0,0 @@
-This content is produced and maintained by the SmartHome/J project.
-
-* Project home: https://www.smarthomej.org
-
-== Declared Project Licenses
-
-This program and the accompanying materials are made available under the terms
-of the Eclipse Public License 2.0 which is available at
-https://www.eclipse.org/legal/epl-2.0/.
-
-== Source Code
-
-https://github.com/smarthomej/addons
-
-Parts of this code have been forked from https://github.com/openhab/openhab-addons
\ No newline at end of file
diff --git a/bundles/org.smarthomej.binding.http/README.md b/bundles/org.smarthomej.binding.http/README.md
deleted file mode 100644
index f701e0a7a0..0000000000
--- a/bundles/org.smarthomej.binding.http/README.md
+++ /dev/null
@@ -1,190 +0,0 @@
-# HTTP Binding
-
-This binding allows using HTTP to bring external data into openHAB or execute HTTP requests on commands.
-
-## Supported Things
-
-Only one thing named `url` is available.
-It can be extended with different channels.
-
-## Thing Configuration
-
-| parameter | optional | default | description |
-|-------------------|----------|---------|-------------|
-| `baseURL` | no | - | The base URL (including protocol `http://` or `https://`) for this thing. Can be extended in channel-configuration. |
-| `refresh` | no | 30 | Time in seconds between two refresh calls for the channels of this thing. |
-| `timeout` | no | 3000 | Timeout for HTTP requests in ms. |
-| `bufferSize` | no | 2048 | The buffer size for the response data (in kB). |
-| `delay` | no | 0 | Delay between two requests in ms (advanced parameter). |
-| `username` | yes | - | Username for authentication (advanced parameter). |
-| `password` | yes | - | Password for authentication (advanced parameter). Also used for the authentication token when using `TOKEN` authentication. |
-| `authMode` | no | BASIC | Authentication mode, `BASIC`, `BASIC_PREEMPTIVE`, `TOKEN` or `DIGEST` (advanced parameter). |
-| `stateMethod` | no | GET | Method used for requesting the state: `GET`, `PUT`, `POST`. |
-| `commandMethod` | no | GET | Method used for sending commands: `GET`, `PUT`, `POST`. |
-| `contentType` | yes | - | MIME content-type of the command requests. Only used for `PUT` and `POST`. |
-| `encoding` | yes | - | Encoding to be used if no encoding is found in responses (advanced parameter). |
-| `headers` | yes | - | Additional headers that are sent along with the request. Format is "header=value". Multiple values can be stored as `headers="key1=value1", "key2=value2", "key3=value3",`|
-| `ignoreSSLErrors` | no | false | If set to true, ignores invalid SSL certificate errors. This is potentially dangerous.|
-| `strictErrorHandling` | no | false | If set to true, thing status is changed depending on last request result (failed = `OFFLINE`). Failed requests result in `UNDEF` for channel values. |
-| `userAgent` | yes | (yes ) | Sets a custom user agent (default is "Jetty/version", e.g. "Jetty/9.4.20.v20190813"). |
-
-*Note:* Optional "no" means that you have to configure a value unless a default is provided, and you are ok with that setting.
-
-*Note:* The `BASIC_PREEMPTIVE` mode adds basic authentication headers even if the server did not request authentication.
-This is dangerous and might be misused.
-The option exists to be able to authenticate when the server is not sending the proper 401/Unauthorized code.
-Authentication might fail if redirections are involved as headers are stripper prior to redirection.
-
-*Note:* If you rate-limit requests by using the `delay` parameter you have to make sure that the time between two refreshes is larger than the time needed for one refresh cycle.
-
-**Attention:** `baseUrl` (and `stateExtension`/`commandExtension`) should not use escaping (e.g. `%22` instead of `"` or `%2c` instead of `,`).
-URLs are properly escaped by the binding itself before the request is sent.
-Using escaped strings in URL parameters may lead to problems with the formatting (see below).
-
-## Channels
-
-The thing has two channels of type `requestDateTime` which provide the timestamp of the last successful (`lastSuccess`) and last failed (`lastFailure`) request.
-
-Additionally, the thing can be extended with data channels.
-Each item type has its own channel-type.
-Depending on the channel-type, channels have different configuration options.
-All channel-types (except `image`) have `stateExtension`, `commandExtension`, `stateTransformation`, `commandTransformation` and `mode` parameters.
-The `image` channel-type supports `stateExtension` only.
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `stateExtension` | yes | - | Appended to the `baseURL` for requesting states. |
-| `commandExtension` | yes | - | Appended to the `baseURL` for sending commands. If empty, same as `stateExtension`. |
-| `stateTransformation ` | yes | - | One or more transformation applied to received values before updating channel. |
-| `commandTransformation` | yes | - | One or more transformation applied to channel value before sending to a remote. |
-| `stateContent` | yes | - | Content for state requests (if method is `PUT` or `POST`) |
-| `mode` | no | `READWRITE` | Mode this channel is allowed to operate. `READONLY` means receive state, `WRITEONLY` means send commands. |
-
-Transformations need to be specified in the same format as
-Some channels have additional parameters.
-When concatenating the `baseURL` and `stateExtension` or `commandExtension` the binding checks if a proper URL part separator (`/`, `&` or `?`) is present and adds a `/` if missing.
-
-### Value Transformations (`stateTransformation`, `commandTransformation`)
-
-Transformations can be used if the supplied value (or the required value) is different from what openHAB internal types require.
-Here are a few examples to unwrap an incoming value via `stateTransformation` from a complex response:
-
-| Received value | Tr. Service | Transformation |
-|---------------------------------------------------------------------|-------------|-------------------------------------------|
-| `{device: {status: { temperature: 23.2 }}}` | JSONPATH | `JSONPATH:$.device.status.temperature` |
-| `23.2` | XPath | `XPath:/device/status/temperature/text()` |
-| `THEVALUE:23.2°C` | REGEX | `REGEX::(.*?)°` |
-
-Transformations can be chained by separating them with the mathematical intersection character "∩".
-Please note that the values will be discarded if one transformation fails (e.g. REGEX did not match).
-
-The same mechanism works for commands (`commandTransformation`) for outgoing values.
-
-### `color`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `onValue` | yes | - | A special value that represents `ON` |
-| `offValue` | yes | - | A special value that represents `OFF` |
-| `increaseValue` | yes | - | A special value that represents `INCREASE` |
-| `decreaseValue` | yes | - | A special value that represents `DECREASE` |
-| `step` | no | 1 | The amount the brightness is increased/decreased on `INCREASE`/`DECREASE` |
-| `colorMode` | no | RGB | Mode for color values: `RGB` or `HSB` |
-
-All values that are not `onValue`, `offValue`, `increaseValue`, `decreaseValue` are interpreted as color value (according to the color mode) in the format `r,g,b` or `h,s,v`.
-
-### `contact`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `openValue` | no | - | A special value that represents `OPEN` |
-| `closedValue` | no | - | A special value that represents `CLOSED` |
-
-### `dimmer`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `onValue` | yes | - | A special value that represents `ON` |
-| `offValue` | yes | - | A special value that represents `OFF` |
-| `increaseValue` | yes | - | A special value that represents `INCREASE` |
-| `decreaseValue` | yes | - | A special value that represents `DECREASE` |
-| `step` | no | 1 | The amount the brightness is increased/decreased on `INCREASE`/`DECREASE` |
-
-All values that are not `onValue`, `offValue`, `increaseValue`, `decreaseValue` are interpreted as brightness 0-100% and need to be numeric only.
-
-### `number`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `unit` | yes | - | The unit label for this channel |
-
-`number` channels can be used for `DecimalType` or `QuantityType` values.
-If a unit is given in the `unit` parameter, the binding tries to create a `QuantityType` state before updating the channel, if no unit is present, it creates a `DecimalType`.
-Please note that incompatible units (e.g. `°C` for a `Number:Density` item) will fail silently, i.e. no error message is logged even if the state update fails.
-
-### `player`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `playValue` | yes | - | A special value that represents `PLAY` |
-| `pauseValue` | yes | - | A special value that represents `PAUSE` |
-| `nextValue` | yes | - | A special value that represents `NEXT` |
-| `previousValue` | yes | - | A special value that represents `PREVIOUS` |
-| `fastforwardValue` | yes | - | A special value that represents `FASTFORWARD` |
-| `rewindValue` | yes | - | A special value that represents `REWIND` |
-
-### `rollershutter`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `upValue` | yes | - | A special value that represents `UP` |
-| `downValue` | yes | - | A special value that represents `DOWN` |
-| `stopValue` | yes | - | A special value that represents `STOP` |
-| `moveValue` | yes | - | A special value that represents `MOVE` |
-
-All values that are not `upValue`, `downValue`, `stopValue`, `moveValue` are interpreted as position 0-100% and need to be numeric only.
-
-### `switch`
-
-| parameter | optional | default | description |
-|-------------------------|----------|-------------|-------------|
-| `onValue` | no | - | A special value that represents `ON` |
-| `offValue` | no | - | A special value that represents `OFF` |
-
-**Note:** Special values need to be exact matches, i.e. no leading or trailing characters and comparison is case-sensitive.
-
-## URL Formatting
-
-After concatenation of the `baseURL` and the `commandExtension` or the `stateExtension` (if provided) the URL is formatted using the [java.util.Formatter](http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html).
-The URL is used as format string and two parameters are added:
-
-- the current date (referenced as `%1$`)
-- the transformed command (referenced as `%2$`)
-
-After the parameter reference the format needs to be appended.
-See the link above for more information about the available format parameters (e.g. to use the string representation, you need to append `s` to the reference, for a timestamp `t`).
-When sending an OFF command on 2020-07-06, the URL
-
-```
-http://www.domain.org/home/lights/23871/?status=%2$s&date=%1$tY-%1$tm-%1$td
-```
-
-is transformed to
-
-```
-http://www.domain.org/home/lights/23871/?status=OFF&date=2020-07-06
-```
-
-## Examples
-
-### `demo.things`
-
-```
-Thing http:url:foo "Foo" [
- baseURL="https://example.com/api/v1/metadata-api/web/metadata",
- headers="key1=value1", "key2=value2", "key3=value3",
- refresh=15] {
- Channels:
- Type string : text "Text" [ stateTransformation="JSONPATH:$.metadata.data" ]
-}
-```
diff --git a/bundles/org.smarthomej.binding.http/pom.xml b/bundles/org.smarthomej.binding.http/pom.xml
deleted file mode 100644
index bae7a262cd..0000000000
--- a/bundles/org.smarthomej.binding.http/pom.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
- 4.0.0
-
-
- org.smarthomej.addons.bundles
- org.smarthomej.addons.reactor.bundles
- 4.2.0-SNAPSHOT
-
-
- org.smarthomej.binding.http
-
- SmartHome/J Add-ons :: Bundles :: HTTP Binding
-
-
- 9.4.53.v20231009
-
-
-
-
- org.smarthomej.addons.bundles
- org.smarthomej.commons
- ${project.version}
- provided
-
-
-
-
- com.github.tomakehurst
- wiremock
- 2.27.2
- test
-
-
- org.eclipse.jetty
- jetty-server
-
-
- org.eclipse.jetty
- jetty-servlet
-
-
- org.eclipse.jetty
- jetty-servlets
-
-
- org.eclipse.jetty
- jetty-proxy
-
-
- org.eclipse.jetty
- jetty-webapp
-
-
-
-
- org.eclipse.jetty
- jetty-server
- ${jetty.version}
- test
-
-
- org.eclipse.jetty
- jetty-servlet
- ${jetty.version}
- test
-
-
- org.eclipse.jetty
- jetty-servlets
- ${jetty.version}
- test
-
-
- org.eclipse.jetty
- jetty-proxy
- ${jetty.version}
- test
-
-
- org.eclipse.jetty
- jetty-webapp
- ${jetty.version}
- test
-
-
-
-
diff --git a/bundles/org.smarthomej.binding.http/src/main/feature/feature.xml b/bundles/org.smarthomej.binding.http/src/main/feature/feature.xml
deleted file mode 100644
index d12b25636c..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/feature/feature.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
- openhab-runtime-base
- mvn:org.smarthomej.addons.bundles/org.smarthomej.commons/${project.version}
- mvn:org.smarthomej.addons.bundles/org.smarthomej.binding.http/${project.version}
-
-
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpBindingConstants.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpBindingConstants.java
deleted file mode 100644
index 2722beb321..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpBindingConstants.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.type.ChannelTypeUID;
-
-/**
- * The {@link HttpBindingConstants} class defines common constants, which are
- * used across the whole binding.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class HttpBindingConstants {
- private static final String BINDING_ID = "http";
-
- public static final ThingTypeUID THING_TYPE_URL = new ThingTypeUID(BINDING_ID, "url");
-
- public static final ChannelTypeUID REQUEST_DATE_TIME_CHANNELTYPE_UID = new ChannelTypeUID(BINDING_ID,
- "requestDateTime");
- public static final String CHANNEL_LAST_SUCCESS = "lastSuccess";
- public static final String CHANNEL_LAST_FAILURE = "lastFailure";
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpClientProvider.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpClientProvider.java
deleted file mode 100644
index 8725e94e70..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpClientProvider.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jetty.client.HttpClient;
-
-/**
- * The {@link HttpClientProvider} defines the interface for providing {@link HttpClient} instances to thing handlers
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public interface HttpClientProvider {
-
- /**
- * get the secure http client
- *
- * @return a HttpClient
- */
- HttpClient getSecureClient();
-
- /**
- * get the insecure http client (ignores SSL errors)
- *
- * @return q HttpClient
- */
- HttpClient getInsecureClient();
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpHandlerFactory.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpHandlerFactory.java
deleted file mode 100644
index 502721dda0..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpHandlerFactory.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal;
-
-import static org.smarthomej.binding.http.internal.HttpBindingConstants.THING_TYPE_URL;
-
-import java.util.Set;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.openhab.core.io.net.http.HttpClientFactory;
-import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.binding.BaseThingHandlerFactory;
-import org.openhab.core.thing.binding.ThingHandler;
-import org.openhab.core.thing.binding.ThingHandlerFactory;
-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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.smarthomej.commons.SimpleDynamicStateDescriptionProvider;
-
-/**
- * The {@link HttpHandlerFactory} is responsible for creating things and thing
- * handlers.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-@Component(configurationPid = "binding.http", service = ThingHandlerFactory.class)
-public class HttpHandlerFactory extends BaseThingHandlerFactory implements HttpClientProvider {
- private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_URL);
- private final Logger logger = LoggerFactory.getLogger(HttpHandlerFactory.class);
-
- private final HttpClient secureClient;
- private final HttpClient insecureClient;
-
- private final SimpleDynamicStateDescriptionProvider httpDynamicStateDescriptionProvider;
-
- @Activate
- public HttpHandlerFactory(@Reference HttpClientFactory httpClientFactory,
- @Reference SimpleDynamicStateDescriptionProvider httpDynamicStateDescriptionProvider) {
- this.secureClient = new HttpClient(new SslContextFactory.Client());
- this.insecureClient = new HttpClient(new SslContextFactory.Client(true));
- // clear user agent, this needs to be set later in the thing configuration as additional header
- this.secureClient.setUserAgentField(null);
- this.insecureClient.setUserAgentField(null);
- try {
- this.secureClient.start();
- this.insecureClient.start();
- } catch (Exception e) {
- // catching exception is necessary due to the signature of HttpClient.start()
- logger.warn("Failed to start http client: {}", e.getMessage());
- throw new IllegalStateException("Could not create HttpClient", e);
- }
- this.httpDynamicStateDescriptionProvider = httpDynamicStateDescriptionProvider;
- }
-
- @Deactivate
- public void deactivate() {
- try {
- secureClient.stop();
- insecureClient.stop();
- } catch (Exception e) {
- // catching exception is necessary due to the signature of HttpClient.stop()
- logger.warn("Failed to stop insecure http client: {}", e.getMessage());
- }
- }
-
- @Override
- public boolean supportsThingType(ThingTypeUID thingTypeUID) {
- return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
- }
-
- @Override
- protected @Nullable ThingHandler createHandler(Thing thing) {
- ThingTypeUID thingTypeUID = thing.getThingTypeUID();
-
- if (THING_TYPE_URL.equals(thingTypeUID)) {
- return new HttpThingHandler(thing, this, httpDynamicStateDescriptionProvider);
- }
-
- return null;
- }
-
- @Override
- public HttpClient getSecureClient() {
- return secureClient;
- }
-
- @Override
- public HttpClient getInsecureClient() {
- return insecureClient;
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpThingHandler.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpThingHandler.java
deleted file mode 100644
index 04a282dde8..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/HttpThingHandler.java
+++ /dev/null
@@ -1,427 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal;
-
-import static org.smarthomej.binding.http.internal.HttpBindingConstants.CHANNEL_LAST_FAILURE;
-import static org.smarthomej.binding.http.internal.HttpBindingConstants.CHANNEL_LAST_SUCCESS;
-import static org.smarthomej.binding.http.internal.HttpBindingConstants.REQUEST_DATE_TIME_CHANNELTYPE_UID;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Base64;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.api.Authentication;
-import org.eclipse.jetty.client.api.AuthenticationStore;
-import org.eclipse.jetty.client.util.BasicAuthentication;
-import org.eclipse.jetty.client.util.DigestAuthentication;
-import org.openhab.core.library.types.DateTimeType;
-import org.openhab.core.library.types.PointType;
-import org.openhab.core.library.types.StringType;
-import org.openhab.core.thing.Channel;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusDetail;
-import org.openhab.core.thing.binding.BaseThingHandler;
-import org.openhab.core.thing.binding.generic.ChannelHandler;
-import org.openhab.core.thing.binding.generic.ChannelHandlerContent;
-import org.openhab.core.thing.binding.generic.ChannelMode;
-import org.openhab.core.thing.binding.generic.ChannelTransformation;
-import org.openhab.core.thing.binding.generic.converter.ColorChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.DimmerChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.FixedValueMappingChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.GenericChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.ImageChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.NumberChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.PlayerChannelHandler;
-import org.openhab.core.thing.binding.generic.converter.RollershutterChannelHandler;
-import org.openhab.core.thing.internal.binding.generic.converter.AbstractTransformingChannelHandler;
-import org.openhab.core.types.Command;
-import org.openhab.core.types.RefreshType;
-import org.openhab.core.types.State;
-import org.openhab.core.types.StateDescription;
-import org.openhab.core.types.StateDescriptionFragmentBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.smarthomej.binding.http.internal.config.HttpChannelConfig;
-import org.smarthomej.binding.http.internal.config.HttpThingConfig;
-import org.smarthomej.binding.http.internal.http.HttpAuthException;
-import org.smarthomej.binding.http.internal.http.HttpResponseListener;
-import org.smarthomej.binding.http.internal.http.HttpStatusListener;
-import org.smarthomej.binding.http.internal.http.RateLimitedHttpClient;
-import org.smarthomej.binding.http.internal.http.RefreshingUrlCache;
-import org.smarthomej.commons.SimpleDynamicStateDescriptionProvider;
-
-/**
- * The {@link HttpThingHandler} is responsible for handling commands, which are
- * sent to one of the channels.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class HttpThingHandler extends BaseThingHandler implements HttpStatusListener {
- private static final Set URL_PART_DELIMITER = Set.of('/', '?', '&');
-
- private final Logger logger = LoggerFactory.getLogger(HttpThingHandler.class);
- private final HttpClientProvider httpClientProvider;
- private final RateLimitedHttpClient rateLimitedHttpClient;
- private final SimpleDynamicStateDescriptionProvider httpDynamicStateDescriptionProvider;
-
- private HttpThingConfig config = new HttpThingConfig();
- private final Map urlHandlers = new HashMap<>();
- private final Map channels = new HashMap<>();
- private final Map channelUrls = new HashMap<>();
-
- public HttpThingHandler(Thing thing, HttpClientProvider httpClientProvider,
- SimpleDynamicStateDescriptionProvider httpDynamicStateDescriptionProvider) {
- super(thing);
- this.httpClientProvider = httpClientProvider;
- this.rateLimitedHttpClient = new RateLimitedHttpClient(httpClientProvider.getSecureClient(), scheduler);
- this.httpDynamicStateDescriptionProvider = httpDynamicStateDescriptionProvider;
- }
-
- @Override
- public void handleCommand(ChannelUID channelUID, Command command) {
- ChannelHandler itemValueConverter = channels.get(channelUID);
- if (itemValueConverter == null) {
- logger.warn("Cannot find channel implementation for channel {}.", channelUID);
- return;
- }
-
- if (command instanceof RefreshType) {
- String key = channelUrls.get(channelUID);
- if (key != null) {
- RefreshingUrlCache refreshingUrlCache = urlHandlers.get(key);
- if (refreshingUrlCache != null) {
- try {
- refreshingUrlCache.get().ifPresentOrElse(itemValueConverter::process, () -> {
- if (config.strictErrorHandling) {
- itemValueConverter.process(null);
- }
- });
- } catch (IllegalArgumentException | IllegalStateException e) {
- logger.warn("Failed processing REFRESH command for channel {}: {}", channelUID, e.getMessage());
- }
- }
- }
- } else {
- try {
- itemValueConverter.send(command);
- } catch (IllegalArgumentException e) {
- logger.warn("Failed to convert command '{}' to channel '{}' for sending", command, channelUID);
- } catch (IllegalStateException e) {
- logger.debug("Writing to read-only channel {} not permitted", channelUID);
- }
- }
- }
-
- @Override
- public void initialize() {
- config = getConfigAs(HttpThingConfig.class);
-
- if (config.baseURL.isEmpty()) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "Parameter baseURL must not be empty!");
- return;
- }
-
- // check protocol is set
- if (!config.baseURL.startsWith("http://") && !config.baseURL.startsWith("https://")) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "baseURL is invalid: protocol not defined.");
- return;
- }
-
- // check SSL handling and initialize client
- if (config.ignoreSSLErrors) {
- logger.info("Using the insecure client for thing '{}'.", thing.getUID());
- rateLimitedHttpClient.setHttpClient(httpClientProvider.getInsecureClient());
- } else {
- logger.info("Using the secure client for thing '{}'.", thing.getUID());
- rateLimitedHttpClient.setHttpClient(httpClientProvider.getSecureClient());
- }
- rateLimitedHttpClient.setDelay(config.delay);
-
- int urlHandlerCount = urlHandlers.size();
- if (urlHandlerCount * config.delay > config.refresh * 1000) {
- // this should prevent the rate limit queue from filling up
- config.refresh = (urlHandlerCount * config.delay) / 1000 + 1;
- logger.warn(
- "{} channels in thing {} with a delay of {} incompatible with the configured refresh time. Refresh-Time increased to the minimum of {}",
- urlHandlerCount, thing.getUID(), config.delay, config.refresh);
- }
-
- // remove empty headers
- config.headers.removeIf(String::isBlank);
-
- // configure authentication
- try {
- AuthenticationStore authStore = rateLimitedHttpClient.getAuthenticationStore();
- URI uri = new URI(config.baseURL);
-
- // clear old auths if available
- Authentication.Result authResult = authStore.findAuthenticationResult(uri);
- if (authResult != null) {
- authStore.removeAuthenticationResult(authResult);
- }
- for (String authType : List.of("Basic", "Digest")) {
- Authentication authentication = authStore.findAuthentication(authType, uri, Authentication.ANY_REALM);
- if (authentication != null) {
- authStore.removeAuthentication(authentication);
- }
- }
-
- if (!config.username.isEmpty() || !config.password.isEmpty()) {
- switch (config.authMode) {
- case BASIC_PREEMPTIVE:
- config.headers.add("Authorization=Basic " + Base64.getEncoder()
- .encodeToString((config.username + ":" + config.password).getBytes()));
- logger.debug("Preemptive Basic Authentication configured for thing '{}'", thing.getUID());
- break;
- case TOKEN:
- if (!config.password.isEmpty()) {
- config.headers.add("Authorization=Bearer " + config.password);
- logger.debug("Token/Bearer Authentication configured for thing '{}'", thing.getUID());
- } else {
- logger.warn("Token/Bearer Authentication configured for thing '{}' but token is empty!",
- thing.getUID());
- }
- break;
- case BASIC:
- authStore.addAuthentication(new BasicAuthentication(uri, Authentication.ANY_REALM,
- config.username, config.password));
- logger.debug("Basic Authentication configured for thing '{}'", thing.getUID());
- break;
- case DIGEST:
- authStore.addAuthentication(new DigestAuthentication(uri, Authentication.ANY_REALM,
- config.username, config.password));
- logger.debug("Digest Authentication configured for thing '{}'", thing.getUID());
- break;
- default:
- logger.warn("Unknown authentication method '{}' for thing '{}'", config.authMode,
- thing.getUID());
- }
- } else {
- logger.debug("No authentication configured for thing '{}'", thing.getUID());
- }
- } catch (URISyntaxException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Cannot create URI from baseUrl.");
- }
- // create channels
- thing.getChannels().forEach(this::createChannel);
-
- updateStatus(ThingStatus.UNKNOWN);
- }
-
- @Override
- public void dispose() {
- // stop update tasks
- urlHandlers.values().forEach(RefreshingUrlCache::stop);
- rateLimitedHttpClient.shutdown();
-
- // clear lists
- urlHandlers.clear();
- channels.clear();
- channelUrls.clear();
-
- // remove state descriptions
- httpDynamicStateDescriptionProvider.removeDescriptionsForThing(thing.getUID());
-
- super.dispose();
- }
-
- /**
- * create all necessary information to handle every channel
- *
- * @param channel a thing channel
- */
- private void createChannel(Channel channel) {
- if (REQUEST_DATE_TIME_CHANNELTYPE_UID.equals(channel.getChannelTypeUID())) {
- // do not generate refreshUrls for lastSuccess / lastFailure channels
- return;
- }
- ChannelUID channelUID = channel.getUID();
- HttpChannelConfig channelConfig = channel.getConfiguration().as(HttpChannelConfig.class);
-
- String stateUrl = concatenateUrlParts(config.baseURL, channelConfig.stateExtension);
- String commandUrl = channelConfig.commandExtension == null ? stateUrl
- : concatenateUrlParts(config.baseURL, channelConfig.commandExtension);
-
- String acceptedItemType = channel.getAcceptedItemType();
- if (acceptedItemType == null) {
- logger.warn("Cannot determine item-type for channel '{}'", channelUID);
- return;
- }
-
- ChannelHandler itemValueConverter;
- switch (acceptedItemType) {
- case "Color":
- itemValueConverter = createChannelHandler(ColorChannelHandler::new, commandUrl, channelUID,
- channelConfig);
- break;
- case "DateTime":
- itemValueConverter = createGenericChannelHandler(commandUrl, channelUID, channelConfig,
- DateTimeType::new);
- break;
- case "Dimmer":
- itemValueConverter = createChannelHandler(DimmerChannelHandler::new, commandUrl, channelUID,
- channelConfig);
- break;
- case "Contact":
- case "Switch":
- itemValueConverter = createChannelHandler(FixedValueMappingChannelHandler::new, commandUrl, channelUID,
- channelConfig);
- break;
- case "Image":
- itemValueConverter = new ImageChannelHandler(state -> updateState(channelUID, state));
- break;
- case "Location":
- itemValueConverter = createGenericChannelHandler(commandUrl, channelUID, channelConfig, PointType::new);
- break;
- case "Number":
- itemValueConverter = createChannelHandler(NumberChannelHandler::new, commandUrl, channelUID,
- channelConfig);
- break;
- case "Player":
- itemValueConverter = createChannelHandler(PlayerChannelHandler::new, commandUrl, channelUID,
- channelConfig);
- break;
- case "Rollershutter":
- itemValueConverter = createChannelHandler(RollershutterChannelHandler::new, commandUrl, channelUID,
- channelConfig);
- break;
- case "String":
- itemValueConverter = createGenericChannelHandler(commandUrl, channelUID, channelConfig,
- StringType::new);
- break;
- default:
- logger.warn("Unsupported item-type '{}'", channel.getAcceptedItemType());
- return;
- }
-
- channels.put(channelUID, itemValueConverter);
- if (channelConfig.mode != ChannelMode.WRITEONLY) {
- // we need a key consisting of stateContent and URL, only if both are equal, we can use the same cache
- String key = channelConfig.stateContent + "$" + stateUrl;
- channelUrls.put(channelUID, key);
- Objects.requireNonNull(urlHandlers.computeIfAbsent(key,
- k -> new RefreshingUrlCache(scheduler, rateLimitedHttpClient, stateUrl, config,
- channelConfig.stateContent, config.contentType, this)))
- .addConsumer(itemValueConverter::process);
- }
-
- StateDescription stateDescription = StateDescriptionFragmentBuilder.create()
- .withReadOnly(channelConfig.mode == ChannelMode.READONLY).build().toStateDescription();
- if (stateDescription != null) {
- // if the state description is not available, we don't need to add it
- httpDynamicStateDescriptionProvider.setDescription(channelUID, stateDescription);
- }
- }
-
- @Override
- public void onHttpError(@Nullable String message) {
- updateState(CHANNEL_LAST_FAILURE, new DateTimeType());
- if (config.strictErrorHandling) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- Objects.requireNonNullElse(message, ""));
- }
- }
-
- @Override
- public void onHttpSuccess() {
- updateState(CHANNEL_LAST_SUCCESS, new DateTimeType());
- updateStatus(ThingStatus.ONLINE);
- }
-
- private void sendHttpValue(String commandUrl, String command) {
- sendHttpValue(commandUrl, command, false);
- }
-
- private void sendHttpValue(String commandUrl, String command, boolean isRetry) {
- try {
- // format URL
- URI uri = Util.uriFromString(String.format(commandUrl, new Date(), command));
-
- // build request
- rateLimitedHttpClient.newPriorityRequest(uri, config.commandMethod, command, config.contentType)
- .thenAccept(request -> {
- request.timeout(config.timeout, TimeUnit.MILLISECONDS);
- config.getHeaders().forEach(request::header);
-
- CompletableFuture<@Nullable ChannelHandlerContent> responseContentFuture = new CompletableFuture<>();
- responseContentFuture.exceptionally(t -> {
- if (t instanceof HttpAuthException) {
- if (isRetry || !rateLimitedHttpClient.reAuth(uri)) {
- logger.warn(
- "Retry after authentication failure failed again for '{}', failing here",
- uri);
- onHttpError("Authorization failed");
- } else {
- sendHttpValue(commandUrl, command, true);
- }
- }
- return null;
- });
-
- if (logger.isTraceEnabled()) {
- logger.trace("Sending to '{}': {}", uri, Util.requestToLogString(request));
- }
-
- request.send(new HttpResponseListener(responseContentFuture, null, config.bufferSize, this));
- });
- } catch (IllegalArgumentException | URISyntaxException | MalformedURLException e) {
- logger.warn("Creating request for '{}' failed: {}", commandUrl, e.getMessage());
- }
- }
-
- private String concatenateUrlParts(String baseUrl, @Nullable String extension) {
- if (extension != null && !extension.isEmpty()) {
- if (!URL_PART_DELIMITER.contains(baseUrl.charAt(baseUrl.length() - 1))
- && !URL_PART_DELIMITER.contains(extension.charAt(0))) {
- return baseUrl + "/" + extension;
- } else {
- return baseUrl + extension;
- }
- } else {
- return baseUrl;
- }
- }
-
- private ChannelHandler createChannelHandler(AbstractTransformingChannelHandler.Factory factory, String commandUrl,
- ChannelUID channelUID, HttpChannelConfig channelConfig) {
- return factory.create(state -> updateState(channelUID, state), command -> postCommand(channelUID, command),
- command -> sendHttpValue(commandUrl, command),
- new ChannelTransformation(channelConfig.stateTransformation),
- new ChannelTransformation(channelConfig.commandTransformation), channelConfig);
- }
-
- private ChannelHandler createGenericChannelHandler(String commandUrl, ChannelUID channelUID,
- HttpChannelConfig channelConfig, Function toState) {
- AbstractTransformingChannelHandler.Factory factory = (state, command, value, stateTrans, commandTrans,
- config) -> new GenericChannelHandler(toState, state, command, value, stateTrans, commandTrans, config);
- return createChannelHandler(factory, commandUrl, channelUID, channelConfig);
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/Util.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/Util.java
deleted file mode 100644
index 2d93209b7d..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/Util.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal;
-
-import java.net.IDN;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jetty.client.api.ContentProvider;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.http.HttpField;
-
-/**
- * The {@link Util} is a utility class
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class Util {
-
- /**
- * create a log string from a {@link org.eclipse.jetty.client.api.Request}
- *
- * @param request the request to log
- * @return the string representing the request
- */
- public static String requestToLogString(Request request) {
- ContentProvider contentProvider = request.getContent();
- String contentString = contentProvider == null ? "null"
- : StreamSupport.stream(contentProvider.spliterator(), false)
- .map(b -> StandardCharsets.UTF_8.decode(b).toString()).collect(Collectors.joining(", "));
- return "Method = {" + request.getMethod() + "}, Headers = {"
- + request.getHeaders().stream().map(HttpField::toString).collect(Collectors.joining(", "))
- + "}, Content = {" + contentString + "}";
- }
-
- /**
- * create an URI from a string, escaping all necessary characters
- *
- * @param s the URI as unescaped string
- * @return URI corresponding to the input string
- * @throws MalformedURLException if parameter is not an URL
- * @throws URISyntaxException if parameter could not be converted to an URI
- */
- public static URI uriFromString(String s) throws MalformedURLException, URISyntaxException {
- URL url = new URL(s);
- URI uri = new URI(url.getProtocol(), url.getUserInfo(), IDN.toASCII(url.getHost()), url.getPort(),
- url.getPath(), url.getQuery(), url.getRef());
- return URI.create(uri.toASCIIString());
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpAuthMode.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpAuthMode.java
deleted file mode 100644
index d49e48d652..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpAuthMode.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.config;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-/**
- * The {@link HttpAuthMode} enum defines the method used for authentication.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public enum HttpAuthMode {
- BASIC_PREEMPTIVE,
- BASIC,
- DIGEST,
- TOKEN
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpChannelConfig.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpChannelConfig.java
deleted file mode 100644
index ed049a8657..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpChannelConfig.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.config;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.thing.binding.generic.ChannelValueConverterConfig;
-
-/**
- * The {@link HttpChannelConfig} class contains fields mapping channel configuration parameters.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class HttpChannelConfig extends ChannelValueConverterConfig {
-
- public @Nullable String stateExtension;
- public @Nullable String commandExtension;
- public @Nullable String stateTransformation;
- public @Nullable String commandTransformation;
- public String stateContent = "";
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpThingConfig.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpThingConfig.java
deleted file mode 100644
index 24556cdb0d..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/config/HttpThingConfig.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.config;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.util.Jetty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The {@link HttpThingConfig} class contains fields mapping thing configuration parameters.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class HttpThingConfig {
- private final Logger logger = LoggerFactory.getLogger(HttpThingConfig.class);
-
- public String baseURL = "";
- public int refresh = 30;
- public int timeout = 3000;
- public int delay = 0;
-
- public String username = "";
- public String password = "";
-
- public HttpAuthMode authMode = HttpAuthMode.BASIC;
- public HttpMethod stateMethod = HttpMethod.GET;
-
- public HttpMethod commandMethod = HttpMethod.GET;
- public int bufferSize = 2048;
-
- public @Nullable String encoding = null;
- public @Nullable String contentType = null;
-
- public boolean ignoreSSLErrors = false;
- public boolean strictErrorHandling = false;
-
- // ArrayList is required as implementation because list may be modified later
- public ArrayList headers = new ArrayList<>();
- public String userAgent = "";
-
- public Map getHeaders() {
- Map headersMap = new HashMap<>();
- // add user agent first, in case it is also defined in the headers, it'll be overwritten
- headersMap.put(HttpHeader.USER_AGENT.asString(),
- userAgent.isBlank() ? "Jetty/" + Jetty.VERSION : userAgent.trim());
- headers.forEach(header -> {
- String[] keyValuePair = header.split("=", 2);
- if (keyValuePair.length == 2) {
- headersMap.put(keyValuePair[0].trim(), keyValuePair[1].trim());
- } else {
- logger.warn("Splitting header '{}' failed. No '=' was found. Ignoring", header);
- }
- });
-
- return headersMap;
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpAuthException.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpAuthException.java
deleted file mode 100644
index de523e225d..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpAuthException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.http;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-/**
- * The {@link HttpAuthException} is an exception after authorization errors
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class HttpAuthException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public HttpAuthException() {
- super();
- }
-
- public HttpAuthException(String message) {
- super(message);
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpResponseListener.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpResponseListener.java
deleted file mode 100644
index 7b9f3f555e..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpResponseListener.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.http;
-
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
-import org.eclipse.jetty.client.util.BufferingResponseListener;
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpStatus;
-import org.openhab.core.thing.binding.generic.ChannelHandlerContent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The {@link HttpResponseListener} is responsible for processing the result of a HTTP request
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class HttpResponseListener extends BufferingResponseListener {
- private final Logger logger = LoggerFactory.getLogger(HttpResponseListener.class);
- private final CompletableFuture<@Nullable ChannelHandlerContent> future;
- private final HttpStatusListener httpStatusListener;
- private final String fallbackEncoding;
-
- /**
- * the HttpResponseListener is responsible
- *
- * @param future Content future to complete with the result of the request
- * @param fallbackEncoding a fallback encoding for the content (UTF-8 if null)
- * @param bufferSize the buffer size for the content in kB (default 2048 kB)
- */
- public HttpResponseListener(CompletableFuture<@Nullable ChannelHandlerContent> future,
- @Nullable String fallbackEncoding, int bufferSize, HttpStatusListener httpStatusListener) {
- super(bufferSize * 1024);
- this.future = future;
- this.fallbackEncoding = fallbackEncoding != null ? fallbackEncoding : StandardCharsets.UTF_8.name();
- this.httpStatusListener = httpStatusListener;
- }
-
- @Override
- public void onComplete(Result result) {
- Response response = result.getResponse();
- if (logger.isTraceEnabled()) {
- logger.trace("Received from '{}': {}", result.getRequest().getURI(), responseToLogString(response));
- }
- Request request = result.getRequest();
- if (response == null || (result.isFailed() && response.getStatus() != 401)) {
- logger.debug("Requesting '{}' (method='{}', content='{}') failed: {}", request.getURI(),
- request.getMethod(), request.getContent(), result.getFailure().getMessage());
- future.complete(null);
- httpStatusListener.onHttpError(result.getFailure().getMessage());
- } else {
- switch (response.getStatus()) {
- case HttpStatus.OK_200:
- case HttpStatus.CREATED_201:
- case HttpStatus.ACCEPTED_202:
- case HttpStatus.NON_AUTHORITATIVE_INFORMATION_203:
- case HttpStatus.NO_CONTENT_204:
- case HttpStatus.RESET_CONTENT_205:
- case HttpStatus.PARTIAL_CONTENT_206:
- case HttpStatus.MULTI_STATUS_207:
- byte[] content = getContent();
- String encoding = getEncoding();
- if (content != null) {
- future.complete(new ChannelHandlerContent(content,
- encoding == null ? fallbackEncoding : encoding, getMediaType()));
- } else {
- future.complete(null);
- }
- httpStatusListener.onHttpSuccess();
- break;
- case HttpStatus.UNAUTHORIZED_401:
- logger.debug("Requesting '{}' (method='{}', content='{}') failed: Authorization error",
- request.getURI(), request.getMethod(), request.getContent());
- future.completeExceptionally(new HttpAuthException());
- break;
- default:
- logger.debug("Requesting '{}' (method='{}', content='{}') failed: {} {}", request.getURI(),
- request.getMethod(), request.getContent(), response.getStatus(), response.getReason());
- future.complete(null);
- httpStatusListener.onHttpError(response.getReason());
- }
- }
- }
-
- private String responseToLogString(Response response) {
- String logString = "Code = {" + response.getStatus() + "}, Headers = {"
- + response.getHeaders().stream().map(HttpField::toString).collect(Collectors.joining(", "))
- + "}, Content = {" + getContentAsString() + "}";
- return logString;
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpStatusListener.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpStatusListener.java
deleted file mode 100644
index 0b1d1d6b8d..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/HttpStatusListener.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.http;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-
-/**
- * The {@link HttpStatusListener} is an interface for reporting HTTP request states
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public interface HttpStatusListener {
- /**
- * report an error
- *
- * @param message optional error message
- */
- void onHttpError(@Nullable String message);
-
- /**
- * report a successful request
- */
- void onHttpSuccess();
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/RateLimitedHttpClient.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/RateLimitedHttpClient.java
deleted file mode 100644
index cde895d2b0..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/RateLimitedHttpClient.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.http;
-
-import java.net.URI;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.Authentication;
-import org.eclipse.jetty.client.api.AuthenticationStore;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.util.StringContentProvider;
-import org.eclipse.jetty.http.HttpMethod;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The {@link RateLimitedHttpClient} is a wrapper for a Jetty HTTP client that limits the number of requests by delaying
- * the request creation
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class RateLimitedHttpClient {
- private static final int MAX_QUEUE_SIZE = 1000; // maximum queue size
- private final Logger logger = LoggerFactory.getLogger(RateLimitedHttpClient.class);
-
- private HttpClient httpClient;
- private int delay = 0; // in ms
- private final ScheduledExecutorService scheduler;
- private final LinkedBlockingQueue requestQueue = new LinkedBlockingQueue<>(MAX_QUEUE_SIZE);
- private final LinkedBlockingQueue priorityRequestQueue = new LinkedBlockingQueue<>(
- MAX_QUEUE_SIZE);
-
- private @Nullable ScheduledFuture> processJob;
-
- public RateLimitedHttpClient(HttpClient httpClient, ScheduledExecutorService scheduler) {
- this.httpClient = httpClient;
- this.scheduler = scheduler;
- }
-
- /**
- * Stop processing the queue and clear it
- */
- public void shutdown() {
- stopProcessJob();
- requestQueue.forEach(RequestQueueEntry::cancel);
- }
-
- /**
- * Set a new delay
- *
- * @param delay in ms between to requests
- */
- public void setDelay(int delay) {
- if (delay < 0) {
- throw new IllegalArgumentException("Delay needs to be larger or equal to zero");
- }
- this.delay = delay;
- stopProcessJob();
- if (delay != 0) {
- processJob = scheduler.scheduleWithFixedDelay(this::processQueue, 0, delay, TimeUnit.MILLISECONDS);
- }
- }
-
- /**
- * Set the HTTP client
- *
- * @param httpClient secure or insecure {@link HttpClient}
- */
- public void setHttpClient(HttpClient httpClient) {
- this.httpClient = httpClient;
- }
-
- /**
- * Create a new request to the given URL respecting rate-limits
- *
- * @param finalUrl the request URL
- * @param method http request method GET/PUT/POST
- * @param content the content (if method PUT/POST)
- * @return a {@link CompletableFuture} that completes with the request
- */
- public CompletableFuture newRequest(URI finalUrl, HttpMethod method, String content,
- @Nullable String contentType) {
- return queueRequest(finalUrl, method, content, contentType, requestQueue);
- }
-
- /**
- * Create a new priority request (executed as next request) to the given URL respecting rate-limits
- *
- * @param finalUrl the request URL
- * @param method http request method GET/PUT/POST
- * @param content the content (if method PUT/POST)
- * @return a {@link CompletableFuture} that completes with the request
- */
- public CompletableFuture newPriorityRequest(URI finalUrl, HttpMethod method, String content,
- @Nullable String contentType) {
- return queueRequest(finalUrl, method, content, contentType, priorityRequestQueue);
- }
-
- private CompletableFuture queueRequest(URI finalUrl, HttpMethod method, String content,
- @Nullable String contentType, LinkedBlockingQueue queue) {
- // if no delay is set, return a completed CompletableFuture
- CompletableFuture future = new CompletableFuture<>();
- RequestQueueEntry queueEntry = new RequestQueueEntry(finalUrl, method, content, contentType, future);
- if (delay == 0) {
- queueEntry.completeFuture(httpClient);
- } else {
- if (!queue.offer(queueEntry)) {
- future.completeExceptionally(new RejectedExecutionException("Maximum queue size exceeded."));
- }
-
- }
- return future;
- }
-
- /**
- * Get the {@link AuthenticationStore} from the wrapped {@link HttpClient}
- *
- * @return the AuthenticationStore of the client
- */
- public AuthenticationStore getAuthenticationStore() {
- return httpClient.getAuthenticationStore();
- }
-
- /**
- * Remove authentication result from the wrapped {@link HttpClient} and force re-auth
- *
- * @param uri the {@link URI} associated with the authentication result
- * @return true if a result was found and cleared, false if not authenticated at all
- */
- public boolean reAuth(URI uri) {
- AuthenticationStore authStore = httpClient.getAuthenticationStore();
- Authentication.Result authResult = authStore.findAuthenticationResult(uri);
- if (authResult != null) {
- authStore.removeAuthenticationResult(authResult);
- logger.debug("Cleared authentication result for '{}', retrying immediately", uri);
- return true;
- } else {
- logger.warn("Could not find authentication result for '{}', failing here", uri);
- return false;
- }
- }
-
- private void stopProcessJob() {
- ScheduledFuture> processJob = this.processJob;
- if (processJob != null) {
- processJob.cancel(false);
- this.processJob = null;
- }
- }
-
- /**
- * Gets an request from either the priority queue or tge regular queue and creates the request
- */
- private void processQueue() {
- RequestQueueEntry queueEntry = priorityRequestQueue.poll();
- if (queueEntry == null) {
- // no entry in priorityRequestQueue, try the regular queue
- queueEntry = requestQueue.poll();
- }
- if (queueEntry != null) {
- queueEntry.completeFuture(httpClient);
- }
- }
-
- private static class RequestQueueEntry {
- private final URI finalUrl;
- private final HttpMethod method;
- private final String content;
- private final @Nullable String contentType;
- private final CompletableFuture future;
-
- public RequestQueueEntry(URI finalUrl, HttpMethod method, String content, @Nullable String contentType,
- CompletableFuture future) {
- this.finalUrl = finalUrl;
- this.method = method;
- this.content = content;
- this.contentType = contentType;
- this.future = future;
- }
-
- /**
- * complete the future with a request
- *
- * @param httpClient the client to create the request
- */
- public void completeFuture(HttpClient httpClient) {
- Request request = httpClient.newRequest(finalUrl).method(method);
- if ((method == HttpMethod.POST || method == HttpMethod.PUT) && !content.isEmpty()) {
- if (contentType == null) {
- request.content(new StringContentProvider(content));
- } else {
- request.content(new StringContentProvider(content), contentType);
- }
- }
- future.complete(request);
- }
-
- /**
- * cancel this request and complete the future with a {@link CancellationException}
- */
- public void cancel() {
- future.completeExceptionally(new CancellationException());
- }
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/RefreshingUrlCache.java b/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/RefreshingUrlCache.java
deleted file mode 100644
index 91f7fa3fac..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/java/org/smarthomej/binding/http/internal/http/RefreshingUrlCache.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http.internal.http;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Date;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.http.HttpMethod;
-import org.openhab.core.thing.binding.generic.ChannelHandlerContent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.smarthomej.binding.http.internal.Util;
-import org.smarthomej.binding.http.internal.config.HttpThingConfig;
-
-/**
- * The {@link RefreshingUrlCache} is responsible for requesting from a single URL and passing the content to the
- * channels
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class RefreshingUrlCache {
- private final Logger logger = LoggerFactory.getLogger(RefreshingUrlCache.class);
-
- private final String url;
- private final RateLimitedHttpClient httpClient;
- private final boolean strictErrorHandling;
- private final int timeout;
- private final int bufferSize;
- private final @Nullable String fallbackEncoding;
- private final Set> consumers = ConcurrentHashMap.newKeySet();
- private final Map headers;
- private final HttpMethod httpMethod;
- private final String httpContent;
- private final @Nullable String httpContentType;
- private final HttpStatusListener httpStatusListener;
-
- private final ScheduledFuture> future;
- private @Nullable ChannelHandlerContent lastContent;
-
- public RefreshingUrlCache(ScheduledExecutorService executor, RateLimitedHttpClient httpClient, String url,
- HttpThingConfig thingConfig, String httpContent, @Nullable String httpContentType,
- HttpStatusListener httpStatusListener) {
- this.httpClient = httpClient;
- this.url = url;
- this.strictErrorHandling = thingConfig.strictErrorHandling;
- this.timeout = thingConfig.timeout;
- this.bufferSize = thingConfig.bufferSize;
- this.httpMethod = thingConfig.stateMethod;
- this.headers = thingConfig.getHeaders();
- this.httpContent = httpContent;
- this.httpContentType = httpContentType;
- this.httpStatusListener = httpStatusListener;
- fallbackEncoding = thingConfig.encoding;
-
- future = executor.scheduleWithFixedDelay(this::refresh, 1, thingConfig.refresh, TimeUnit.SECONDS);
- logger.trace("Started refresh task for URL '{}' with interval {}s", url, thingConfig.refresh);
- }
-
- private void refresh() {
- refresh(false);
- }
-
- private void refresh(boolean isRetry) {
- if (consumers.isEmpty()) {
- // do not refresh if we don't have listeners
- return;
- }
-
- // format URL
- try {
- URI uri = Util.uriFromString(String.format(this.url, new Date()));
- logger.trace("Requesting refresh (retry={}) from '{}' with timeout {}ms", isRetry, uri, timeout);
-
- httpClient.newRequest(uri, httpMethod, httpContent, httpContentType).thenAccept(request -> {
- request.timeout(timeout, TimeUnit.MILLISECONDS);
- headers.forEach(request::header);
-
- CompletableFuture<@Nullable ChannelHandlerContent> responseContentFuture = new CompletableFuture<>();
- responseContentFuture.exceptionally(t -> {
- if (t instanceof HttpAuthException) {
- if (isRetry || !httpClient.reAuth(uri)) {
- logger.debug("Authentication failed for '{}', retry={}", uri, isRetry);
- httpStatusListener.onHttpError("Authorization failed");
- } else {
- refresh(true);
- }
- }
- return null;
- }).thenAccept(this::processResult);
-
- if (logger.isTraceEnabled()) {
- logger.trace("Sending to '{}': {}", uri, Util.requestToLogString(request));
- }
-
- request.send(new HttpResponseListener(responseContentFuture, fallbackEncoding, bufferSize,
- httpStatusListener));
- }).exceptionally(e -> {
- if (e instanceof CancellationException) {
- logger.debug("Request to URL {} was cancelled by thing handler.", uri);
- } else {
- logger.warn("Request to URL {} failed: {}", uri, e.getMessage());
- }
- return null;
- });
- } catch (IllegalArgumentException | URISyntaxException | MalformedURLException e) {
- logger.warn("Creating request for '{}' failed: {}", url, e.getMessage());
- }
- }
-
- public void stop() {
- // clearing all listeners to prevent further updates
- consumers.clear();
- future.cancel(false);
- logger.trace("Stopped refresh task for URL '{}'", url);
- }
-
- public void addConsumer(Consumer<@Nullable ChannelHandlerContent> consumer) {
- consumers.add(consumer);
- }
-
- public Optional get() {
- return Optional.ofNullable(lastContent);
- }
-
- private void processResult(@Nullable ChannelHandlerContent content) {
- if (content != null || strictErrorHandling) {
- for (Consumer<@Nullable ChannelHandlerContent> consumer : consumers) {
- try {
- consumer.accept(content);
- } catch (IllegalArgumentException | IllegalStateException e) {
- logger.warn("Failed processing result for URL {}: {}", url, e.getMessage());
- }
- }
- }
- lastContent = content;
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/addon/addon.xml
deleted file mode 100644
index a2c9d6cf1d..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/addon/addon.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- binding
- HTTP Binding
- This is the binding for retrieving and processing HTTP resources.
-
-
diff --git a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/config/config.xml b/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/config/config.xml
deleted file mode 100644
index 82cd4456a9..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/config/config.xml
+++ /dev/null
@@ -1,431 +0,0 @@
-
-
-
-
-
-
- Transformation pattern used when receiving values. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending values. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
-
-
- Transformation pattern used when receiving values.
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
- The value that represents ON
-
-
-
- The value that represents OFF
-
-
-
- The value that represents INCREASE
-
-
-
- The value that represents DECREASE
-
-
-
- The value by which the current brightness is increased/decreased if the corresponding command is
- received
- 1
-
-
-
- Color mode for parsing incoming and sending outgoing values
-
-
-
-
- true
- RGB
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
-
-
- Transformation pattern used when receiving value. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
- The value that represents OPEN
-
-
-
- The value that represents CLOSED
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
-
-
- Transformation pattern used when receiving value. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
- The value that represents ON
-
-
-
- The value that represents OFF
-
-
-
- The value that represents INCREASE
-
-
-
- The value that represents DECREASE
-
-
-
- The value by which the current brightness is increased/decreased if the corresponding command is
- received
- 1
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
-
-
-
- Transformation pattern used when receiving value. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
- Unit to append to the (transformed) value.
- true
-
-
-
-
-
-
- Transformation pattern used when receiving value. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
- The value that represents PLAY
-
-
-
- The value that represents PAUSE
-
-
-
- The value that represents NEXT
-
-
-
- The value that represents PREVIOUS
-
-
-
- The value that represents REWIND
-
-
-
- The value that represents FASTFORWARD
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
-
-
- Transformation pattern used when receiving value. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
- The value that represents UP
-
-
-
- The value that represents DOWN
-
-
-
- The value that represents STOP
-
-
-
- The value that represents MOVE
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
-
-
- Transformation pattern used when receiving value. Multiple transformation can be chained using "∩".
-
-
-
- Transformation pattern used when sending value. Multiple transformation can be chained using "∩".
-
-
-
- This value is added to the base URL configured in the thing for retrieving values.
- true
-
-
-
- This value is added to the base URL configured in the thing for sending values.
- true
-
-
-
- Content for state request (only used if method is POST/PUT)
- true
-
-
-
- The value that represents ON
-
-
-
- The value that represents OFF
-
-
-
-
-
-
-
-
- true
- true
- READWRITE
-
-
-
-
diff --git a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/thing/thing-types.xml
deleted file mode 100644
index 2cc7be53ef..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/thing/thing-types.xml
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
- Represents a base URL and all associated requests.
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
- The URL set here can be extended in the channel configuration.
- url
-
-
-
- Time between two refreshes of all channels
- 30
-
-
-
- The timeout in ms for each request
- 3000
-
-
-
- Delay between to requests
- 0
- true
-
-
-
- Size of the response buffer (default 2048 kB)
- 2048
- true
-
-
-
- Basic Authentication username
- true
-
-
-
- Authentication password or token
- password
- true
-
-
-
-
-
-
-
-
-
- BASIC
- true
- true
-
-
-
- HTTP method (GET,POST, PUT) for retrieving a status.
-
-
-
-
-
- true
- GET
- true
-
-
-
- HTTP method (GET,POST, PUT) for sending commands.
-
-
-
-
-
- true
- GET
- true
-
-
-
- The MIME content type. Only used for `POST` and `PUT`.
-
-
-
-
-
-
-
- true
-
-
-
- Fallback Encoding text received by this thing's channels.
- true
-
-
-
- Additional headers send along with the request
- false
- true
-
-
-
- If set to true ignores invalid SSL certificate errors. This is potentially dangerous.
- false
- true
-
-
-
- Sets a custom user agent (default is "Jetty/version", e.g. "Jetty/9.4.20.v20190813").
- true
-
-
-
-
-
- DateTime
-
-
-
-
-
- Color
-
-
-
-
-
- Contact
-
-
-
-
-
- DateTime
-
-
-
-
-
- Dimmer
-
-
-
-
-
- Image
-
-
-
-
-
- Location
-
-
-
-
-
- Number
-
-
-
-
-
- Player
-
-
-
-
-
- Rollershutter
-
-
-
-
-
- String
-
-
-
-
-
- Switch
-
-
-
-
-
diff --git a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/update/instructions.xml b/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/update/instructions.xml
deleted file mode 100644
index 7343854b90..0000000000
--- a/bundles/org.smarthomej.binding.http/src/main/resources/OH-INF/update/instructions.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
- http:requestDateTime
-
-
-
- http:requestDateTime
-
-
-
-
-
-
diff --git a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/AbstractWireMockTest.java b/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/AbstractWireMockTest.java
deleted file mode 100644
index 7a40b19d9d..0000000000
--- a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/AbstractWireMockTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.removeAllMappings;
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
-
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jetty.client.HttpClient;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
-import org.openhab.core.test.TestPortUtil;
-import org.openhab.core.test.java.JavaTest;
-import org.smarthomej.binding.http.internal.http.RateLimitedHttpClient;
-
-import com.github.tomakehurst.wiremock.WireMockServer;
-import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
-
-/**
- * The {@link AbstractWireMockTest} implements tests for the {@link RateLimitedHttpClient}
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public abstract class AbstractWireMockTest extends JavaTest {
- protected int port = 0;
- protected @NonNullByDefault({}) WireMockServer wireMockServer;
- protected @NonNullByDefault({}) HttpClient httpClient;
- protected ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
-
- @BeforeAll
- public void initAll() throws Exception {
- port = TestPortUtil.findFreePort();
-
- wireMockServer = new WireMockServer(options().port(port).extensions(new ResponseTemplateTransformer(false)));
- wireMockServer.start();
-
- httpClient = new HttpClient();
- httpClient.start();
-
- configureFor("localhost", port);
- }
-
- @AfterEach
- public void cleanUpTest() {
- removeAllMappings();
- }
-
- @AfterAll
- public void cleanUpAll() throws Exception {
- wireMockServer.shutdown();
- scheduler.shutdown();
- httpClient.stop();
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/RateLimitedHttpClientTest.java b/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/RateLimitedHttpClientTest.java
deleted file mode 100644
index 84ba72d509..0000000000
--- a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/RateLimitedHttpClientTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.get;
-import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.lessThan;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-
-import java.net.URI;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.http.HttpMethod;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.smarthomej.binding.http.internal.http.RateLimitedHttpClient;
-
-/**
- * The {@link RateLimitedHttpClientTest} implements tests for the {@link RateLimitedHttpClient}
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-public class RateLimitedHttpClientTest extends AbstractWireMockTest {
- private static final String TEST_LOCATION = "/testlocation";
- private static final String TEST_CONTENT = "TESTCONTENT";
-
- private List responses = new CopyOnWriteArrayList<>();
-
- @AfterEach
- public void cleanUpTest() {
- responses.clear();
- super.cleanUpTest();
- }
-
- @Test
- public void testWithoutLimit() {
- doLimitTest(0, List.of(false, false));
-
- // we except to receive the responses in the correct order
- assertEquals(0, responses.get(0).seqNumber);
- assertEquals(1, responses.get(1).seqNumber);
-
- // we expect a short delay between both requests, but less than 100ms
- long msBetween = responses.get(1).time - responses.get(0).time;
- assertThat((int) msBetween, allOf(greaterThanOrEqualTo(0), lessThan(100)));
- }
-
- @Test
- public void testWithLimit() {
- doLimitTest(500, List.of(false, false));
- // we except to receive the responses in the correct order
- assertEquals(0, responses.get(0).seqNumber);
- assertEquals(1, responses.get(1).seqNumber);
-
- // we expect at least 500ms delay between both requests, but less than 500+100=600ms
- long msBetween = responses.get(1).time - responses.get(0).time;
- assertThat((int) msBetween, allOf(greaterThanOrEqualTo(500), lessThan(600)));
- }
-
- @Test
- public void testWithLimitAndPriority() {
- doLimitTest(500, List.of(false, false, true));
-
- // we expect to receive the responses of request 3 before request two, exact order of 1 and 3 depends on timing,
- // so accept both
- assertThat(responses.get(0).seqNumber, anyOf(equalTo(0), equalTo(2)));
- assertThat(responses.get(1).seqNumber, anyOf(equalTo(0), equalTo(2)));
- assertNotEquals(responses.get(1).seqNumber, responses.get(0).seqNumber);
- assertEquals(1, responses.get(2).seqNumber);
-
- // we expect at least 2*500=1000ms delay between the first and last request, but less than 2*500+100=1100 ms
- long msBetween = responses.get(2).time - responses.get(0).time;
- assertThat((int) msBetween, allOf(greaterThanOrEqualTo(1000), lessThan(1100)));
- }
-
- private List doLimitTest(int setDelay, List config) {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withBody(TEST_CONTENT)));
-
- RateLimitedHttpClient rateLimitedHttpClient = new RateLimitedHttpClient(httpClient, scheduler);
- rateLimitedHttpClient.setDelay(setDelay);
-
- URI url = URI.create("http://localhost:" + port + TEST_LOCATION);
- int seqNumber = 0;
-
- for (boolean priority : config) {
- int nextSeqNumber = seqNumber++;
- CompletableFuture requestFuture;
-
- if (priority) {
- requestFuture = rateLimitedHttpClient.newPriorityRequest(url, HttpMethod.GET, "", null);
- } else {
- requestFuture = rateLimitedHttpClient.newRequest(url, HttpMethod.GET, "", null);
- }
-
- requestFuture.thenAccept(request -> {
- try {
- responses.add(new Response(nextSeqNumber, request.send()));
- } catch (Exception e) {
- }
- });
- }
-
- // wait until we got all results
- waitForAssert(() -> assertEquals(config.size(), responses.size()));
- rateLimitedHttpClient.shutdown();
-
- return responses;
- }
-
- private static class Response {
- public final int seqNumber;
- public final long time = System.currentTimeMillis();
- public final String content;
-
- public Response(int seqNumber, ContentResponse contentResponse) {
- this.seqNumber = seqNumber;
- this.content = contentResponse.getContentAsString();
- }
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/RefreshingUrlCacheTest.java b/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/RefreshingUrlCacheTest.java
deleted file mode 100644
index fad6c7968b..0000000000
--- a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/RefreshingUrlCacheTest.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.get;
-import static com.github.tomakehurst.wiremock.client.WireMock.post;
-import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockingDetails;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.util.Jetty;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.openhab.core.thing.binding.generic.ChannelHandlerContent;
-import org.smarthomej.binding.http.internal.config.HttpThingConfig;
-import org.smarthomej.binding.http.internal.http.HttpStatusListener;
-import org.smarthomej.binding.http.internal.http.RateLimitedHttpClient;
-import org.smarthomej.binding.http.internal.http.RefreshingUrlCache;
-
-/**
- * The {@link RefreshingUrlCacheTest} implements tests for the {@link RefreshingUrlCache}
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-public class RefreshingUrlCacheTest extends AbstractWireMockTest {
- private static final String TEST_LOCATION = "/testlocation";
- private static final String TEST_CONTENT = "TESTCONTENT";
-
- private @NonNullByDefault({}) RateLimitedHttpClient rateLimitedHttpClient;
- private @NonNullByDefault({}) HttpThingConfig thingConfig;
- private @NonNullByDefault({}) String url;
- private @NonNullByDefault({}) HttpStatusListener statusListener;
-
- private final List<@Nullable ChannelHandlerContent> contentWrappers = new CopyOnWriteArrayList<>();
-
- @BeforeEach
- public void initTest() {
- // this is usually done inside the HttpHandlerFactory when creating the clients
- httpClient.setUserAgentField(null);
-
- // create a RateLimitedHttpClient
- rateLimitedHttpClient = new RateLimitedHttpClient(httpClient, scheduler);
- rateLimitedHttpClient.setDelay(0);
- statusListener = mock(HttpStatusListener.class);
-
- // initialize thing config with some default values
- thingConfig = new HttpThingConfig();
- thingConfig.baseURL = "http://localhost:" + port;
- thingConfig.timeout = 500;
- thingConfig.refresh = 1;
-
- url = thingConfig.baseURL + TEST_LOCATION;
- }
-
- @AfterEach
- public void cleanUpTest() {
- rateLimitedHttpClient.shutdown();
- contentWrappers.clear();
- super.cleanUpTest();
- }
-
- @Test
- public void testUpdateOnSuccessfulRequest() {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withBody(TEST_CONTENT)));
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // wait until we got at least four results or timeout (after 10s)
- waitForAssert(() -> assertEquals(4, contentWrappers.size()));
- urlCache.stop();
-
- // verify we did not have errors and the number of responses matches the number of success calls
- verify(statusListener, never()).onHttpError(any());
- verify(statusListener, times(contentWrappers.size())).onHttpSuccess();
-
- // assert all content equals the correct value
- assertTrue(contentWrappers.stream().map(Objects::requireNonNull).map(ChannelHandlerContent::getAsString)
- .allMatch(TEST_CONTENT::equals));
- }
-
- @Test
- public void testNoUpdateOn404ErrorInNormalMode() {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withStatus(404)));
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // verify we get at least two error reports in 3s
- verify(statusListener, timeout(3000).atLeast(2)).onHttpError(any());
- verify(statusListener, never()).onHttpSuccess();
- urlCache.stop();
-
- // assert all content equals the correct value
- assertEquals(true, contentWrappers.isEmpty());
- }
-
- @Test
- public void testNullUpdateOn404ErrorInStrictMode() {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withStatus(404)));
- thingConfig.strictErrorHandling = true;
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // verify we get at least two error reports in 3s
- verify(statusListener, timeout(3000).atLeast(2)).onHttpError(any());
- verify(statusListener, never()).onHttpSuccess();
- urlCache.stop();
-
- int totalErrorCalls = mockingDetails(statusListener).getInvocations().size();
-
- // assert we have the same number of consumer calls as error calls and all are null
- assertEquals(totalErrorCalls, contentWrappers.size());
- assertEquals(true, contentWrappers.stream().allMatch(Objects::isNull));
- }
-
- @Test
- public void testNoUpdateOnRequestTimedOutInNormalMode() {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withFixedDelay(1000).withStatus(200)));
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // verify we get at least two error reports in 3s
- verify(statusListener, timeout(3000).atLeast(2)).onHttpError(any());
- verify(statusListener, never()).onHttpSuccess();
- urlCache.stop();
-
- // assert all content equals the correct value
- assertEquals(true, contentWrappers.isEmpty());
- }
-
- @Test
- public void testNullUpdateOnRequestTimedOutInStrictMode() {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withFixedDelay(1000).withStatus(200)));
- thingConfig.strictErrorHandling = true;
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // verify we get at least two error reports in 3s
- verify(statusListener, timeout(3000).atLeast(2)).onHttpError(any());
- verify(statusListener, never()).onHttpSuccess();
- urlCache.stop();
-
- int totalErrorCalls = mockingDetails(statusListener).getInvocations().size();
-
- // assert we have the same number of consumer calls as error calls and all are null
- assertEquals(totalErrorCalls, contentWrappers.size());
- assertEquals(true, contentWrappers.stream().allMatch(Objects::isNull));
- }
-
- @Test
- public void testAdditionalHeaderIsSentWithRequest() {
- String testHeaderKey = "X-SMARTHOME";
- String testHeaderValue = "TESTVALUE";
-
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse()
- .withBody("{{request.headers." + testHeaderKey + "}}").withTransformers("response-template")));
- thingConfig.headers = new ArrayList<>(List.of(testHeaderKey + "=" + testHeaderValue));
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // we need only one answer
- waitForAssert(() -> assertFalse(contentWrappers.isEmpty()));
- urlCache.stop();
-
- String returnedHeaderValue = Objects.requireNonNull(contentWrappers.get(0)).getAsString();
- assertEquals(testHeaderValue, returnedHeaderValue);
- }
-
- @Test
- public void testUserAgentIsJettyWhenNotConfigured() {
- stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(
- aResponse().withBody("{{request.headers.User-Agent}}").withTransformers("response-template")));
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // we need only one answer
- waitForAssert(() -> assertFalse(contentWrappers.isEmpty()));
- urlCache.stop();
-
- String returnedHeaderValue = Objects.requireNonNull(contentWrappers.get(0)).getAsString();
- assertEquals("Jetty/" + Jetty.VERSION, returnedHeaderValue);
- }
-
- @Test
- public void testContentSentAlongWithPost() {
- stubFor(post(urlEqualTo(TEST_LOCATION))
- .willReturn(aResponse().withBody("{{request.body}}").withTransformers("response-template")));
- thingConfig.stateMethod = HttpMethod.POST;
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // we need only one answer
- waitForAssert(() -> assertFalse(contentWrappers.isEmpty()));
- urlCache.stop();
-
- String returnedBody = Objects.requireNonNull(contentWrappers.get(0)).getAsString();
- assertEquals(TEST_CONTENT, returnedBody);
- }
-
- @Test
- public void testDateIsFormattedInURL() {
- stubFor(get(urlPathEqualTo(TEST_LOCATION))
- .willReturn(aResponse().withBody("{{request.query.date}}").withTransformers("response-template")));
- url += "?date=%1$tY-%1$tm-%1$td";
-
- RefreshingUrlCache urlCache = getUrlCache(TEST_CONTENT);
-
- // we need only one answer
- waitForAssert(() -> assertFalse(contentWrappers.isEmpty()));
- urlCache.stop();
-
- String returnedQueryValue = Objects.requireNonNull(contentWrappers.get(0)).getAsString();
- assertTrue(returnedQueryValue.matches("\\d{4}-\\d{2}-\\d{2}"));
- }
-
- /**
- * helper method to create a {@link RefreshingUrlCache} and add a test listener
- *
- * @param content HTTP content
- * @return the cache object
- */
- private RefreshingUrlCache getUrlCache(String content) {
- RefreshingUrlCache urlCache = new RefreshingUrlCache(scheduler, rateLimitedHttpClient, url, thingConfig,
- content, null, statusListener);
- urlCache.addConsumer(contentWrappers::add);
-
- return urlCache;
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/UtilTest.java b/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/UtilTest.java
deleted file mode 100644
index 728bc368be..0000000000
--- a/bundles/org.smarthomej.binding.http/src/test/java/org/smarthomej/binding/http/UtilTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * Copyright (c) 2021-2023 Contributors to the SmartHome/J 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.smarthomej.binding.http;
-
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.smarthomej.binding.http.internal.Util;
-
-/**
- * The {@link UtilTest} is a test class for URL encoding
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-public class UtilTest {
-
- @Test
- public void uriUTF8InHostnameEncodeTest() throws MalformedURLException, URISyntaxException {
- String s = "https://foöo.bar/zhu.html?str=zin&tzz=678";
- Assertions.assertEquals("https://xn--foo-tna.bar/zhu.html?str=zin&tzz=678", Util.uriFromString(s).toString());
- }
-
- @Test
- public void uriUTF8InPathEncodeTest() throws MalformedURLException, URISyntaxException {
- String s = "https://foo.bar/zül.html?str=zin";
- Assertions.assertEquals("https://foo.bar/z%C3%BCl.html?str=zin", Util.uriFromString(s).toString());
- }
-
- @Test
- public void uriUTF8InQueryEncodeTest() throws MalformedURLException, URISyntaxException {
- String s = "https://foo.bar/zil.html?str=zän";
- Assertions.assertEquals("https://foo.bar/zil.html?str=z%C3%A4n", Util.uriFromString(s).toString());
- }
-
- @Test
- public void uriSpaceInPathEncodeTest() throws MalformedURLException, URISyntaxException {
- String s = "https://foo.bar/z l.html?str=zun";
- Assertions.assertEquals("https://foo.bar/z%20l.html?str=zun", Util.uriFromString(s).toString());
- }
-
- @Test
- public void uriSpaceInQueryEncodeTest() throws MalformedURLException, URISyntaxException {
- String s = "https://foo.bar/zzl.html?str=z n";
- Assertions.assertEquals("https://foo.bar/zzl.html?str=z%20n", Util.uriFromString(s).toString());
- }
-}
diff --git a/bundles/org.smarthomej.binding.http/xtend_examples.md b/bundles/org.smarthomej.binding.http/xtend_examples.md
deleted file mode 100644
index 50b492fceb..0000000000
--- a/bundles/org.smarthomej.binding.http/xtend_examples.md
+++ /dev/null
@@ -1,63 +0,0 @@
-## Vito WIFI (https://github.com/openhab/openhab-addons/issues/9480#issuecomment-751335696)
-
-### .things
-```
-Thing http:url:vitowifi "VitoWifi" @ "1stfloor" [baseURL="http://192.168.1.61/", commandMethod="POST", delay="1000", refresh="90", timeout="900"] {
-
- Channels:
- Type number : Channel_Vito_ID "Vito_ID" [ stateExtension="read?DP=0x00f8&Type=CountS", stateTransformation="REGEX:(^[-+]?[0-9]+)" ]
- Type number : Channel_Vito_Mode "Vito_Mode" [ stateExtension="read?DP=0xb000&Type=Mode", stateTransformation="REGEX:(^[-+]?[0-9]+)", commandExtension="write?DP=0xb000&Type=Mode&Value=%2$s" ]
- Type number : Channel_Vito_OnOff "Vito_OnOff_for_ESPEasy" [ stateExtension="control?cmd=Status,GPIO,12", stateTransformation="JSONPATH(state)",commandExtension="control?cmd=GPIO,12,%2$s"]
-}
-```
-
-### .items
-
-```
-Number Vito_ID "Vito_ID" (gHeating) {channel="http:url:vitowifi:Channel_Vito_ID" , expire="5m" }
-Number Vito_Mode "Vito_Mode" (gHeating) {channel="http:url:vitowifi:Channel_Vito_Mode" , expire="5m" }// 0= Off 1= WW 2= WW+heat 0x42 (66)=party
-Number Vito_OnOff "ONOFF Switch" (gHeating) {channel="http:url:vitowifi:Channel_Vito_OnOff" , expire="5m" }
-```
-
-## Feinstaubsensor (https://community.openhab.org/t/http-binding-openhab-3-version/101851/235)
-
-The http request http://feinstaubsensor-14255834/data.json is answering with a JSON string.
-So I need some simple JSONPATH transformation and one java script transformation.
-Data is polled every 10 seconds.
-
-### .things
-
-```
-Thing http:url:feinstaub "Feinstaub" [ baseURL="http://feinstaubsensor-14255834/data.json", refresh=10] {
- Channels:
- Type number : SDS_PM10 [ stateTransformation="JSONPATH:$.sensordatavalues[0].value" ]
- Type number : SDS_PM25 [ stateTransformation="JSONPATH:$.sensordatavalues[1].value" ]
- Type number : Temperatur [ stateTransformation="JSONPATH:$.sensordatavalues[2].value" ]
- Type number : Pressure [ stateTransformation="JS:airpressure.js" ]
- Type number : Humidity [ stateTransformation="JSONPATH:$.sensordatavalues[4].value" ]
-}
-```
-
-### .items
-
-```
-/* **************************
- * Feinstaub sensor data
- * ************************** */
- Number N_FS_SDS_PM10 "Partikelgröße 10µm [%.2f µg/m³]" { channel="http:url:feinstaub:SDS_PM10" }
- Number N_FS_SDS_PM25 "Partikelgröße 2.5µm [%.2f µg/m³]" { channel="http:url:feinstaub:SDS_PM25" }
- Number N_FS_Temperatur "Temperatur [%.2f °C]" { channel="http:url:feinstaub:Temperatur" }
- Number N_FS_Pressure "Luftdruck [%.2f hPa]" { channel="http:url:feinstaub:Pressure" }
- Number N_FS_Humidity "Luftfeuchte [%.2f %%]" { channel="http:url:feinstaub:Humidity" }
-```
-
-### airpressure.js (transformation)
-
-I have a BME2080 sensor connected. The Humidity must be diveded by 100 to show hPa.
-
-```
-(function(x) {
- var json = JSON.parse(x);
- return json.sensordatavalues[3].value/100;
-})(input)
-```
\ No newline at end of file
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 00c033c0c8..f552b592f9 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -24,7 +24,6 @@
org.smarthomej.binding.androiddebugbridgeorg.smarthomej.binding.amazonechocontrol
- org.smarthomej.binding.httporg.smarthomej.binding.notificationsforfiretvorg.smarthomej.binding.tcpudporg.smarthomej.binding.telenot