mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
"Cacheability" option for critical REST resources (#3335)
* Closes #3329. This implements a new optional `cacheable` parameter for these REST endpoints: - `/rest/items` - `/rest/things` - `/rest/rules` When this parameter is set, a flat list of all elements excluding non-cacheable fields (e.g. "state", "transformedState", "stateDescription", "commandDescription" for items, "statusInfo", "firmwareStatus", "properties" for things, "status" for rules) will be retrieved along with a `Last-Modified` HTTP response header. When unknown, the Last-Modified header will be set to the date of the request. Also only when this parameter is set, and a `If-Modified-Since` header is found in the request, that header will be compared to the last known modified date for the corresponding cacheable list. The last modified date will be reset when any change is made on the elements of the underlying registry. If the `If-Modified-Since` date is equal or more recent than the last modified date, then a 304 Not Modified response with no content will be served instead of the usual 200 OK, informing the client that its cache is still valid at the provided date. All other request parameters will be ignored except for "metadata" in the `/rest/items` endpoint. When a metadata selector is set, the resulting item list will be considered like a completely different resource, i.e. it will have its own last modified date. Regarding metadata, the approach to invalidating last modified dates is very conservative: when any metadata is changed, all cacheable lists of items will have their last modified date reset even if the change was in a metadata namespace that wasn't requested. This also implements the abovedescribed behavior for the `/rest/ui/components/{namespace}` endpoint, but no `cacheable` parameter is necessary. The last modified date is tracked by namespace. Signed-off-by: Yannick Schaus <github@schaus.net>
This commit is contained in:
+24
-15
@@ -30,6 +30,7 @@ import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Request;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
@@ -94,6 +95,7 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
|
||||
private @Mock @NonNullByDefault({}) ItemProvider itemProviderMock;
|
||||
private @Mock @NonNullByDefault({}) UriBuilder uriBuilderMock;
|
||||
private @Mock @NonNullByDefault({}) UriInfo uriInfoMock;
|
||||
private @Mock @NonNullByDefault({}) Request request;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
@@ -127,7 +129,8 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
|
||||
public void shouldReturnUnicodeItems() throws IOException, TransformationException {
|
||||
item4.setLabel(ITEM_LABEL4);
|
||||
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, null, null, false, null);
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, null, null, false,
|
||||
null, false);
|
||||
assertThat(readItemLabelsFromResponse(response), hasItems(ITEM_LABEL4));
|
||||
}
|
||||
|
||||
@@ -147,28 +150,31 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
|
||||
item3.addTag("Tag2");
|
||||
item4.addTag("Tag4");
|
||||
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "Tag1", null, false, null);
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "Tag1", null,
|
||||
false, null, false);
|
||||
assertThat(readItemNamesFromResponse(response), hasItems(ITEM_NAME1, ITEM_NAME2));
|
||||
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "Tag2", null, false, null);
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "Tag2", null, false, null,
|
||||
false);
|
||||
assertThat(readItemNamesFromResponse(response), hasItems(ITEM_NAME2, ITEM_NAME3));
|
||||
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "NotExistingTag", null, false, null);
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "NotExistingTag", null,
|
||||
false, null, false);
|
||||
assertThat(readItemNamesFromResponse(response), hasSize(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFilterItemsByType() throws Exception {
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, CoreItemFactory.SWITCH, null,
|
||||
null, false, null);
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, CoreItemFactory.SWITCH,
|
||||
null, null, false, null, false);
|
||||
assertThat(readItemNamesFromResponse(response), hasItems(ITEM_NAME1, ITEM_NAME2));
|
||||
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, CoreItemFactory.DIMMER, null, null, false,
|
||||
null);
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, CoreItemFactory.DIMMER, null,
|
||||
null, false, null, false);
|
||||
assertThat(readItemNamesFromResponse(response), hasItems(ITEM_NAME3));
|
||||
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, CoreItemFactory.COLOR, null, null, false,
|
||||
null);
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, CoreItemFactory.COLOR, null, null,
|
||||
false, null, false);
|
||||
assertThat(readItemNamesFromResponse(response), hasSize(0));
|
||||
}
|
||||
|
||||
@@ -176,15 +182,18 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
|
||||
public void shouldAddAndRemoveTags() throws Exception {
|
||||
managedItemProvider.add(new SwitchItem("Switch"));
|
||||
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "MyTag", null, false, null);
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "MyTag", null,
|
||||
false, null, false);
|
||||
assertThat(readItemNamesFromResponse(response), hasSize(0));
|
||||
|
||||
itemResource.addTag("Switch", "MyTag");
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "MyTag", null, false, null);
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "MyTag", null, false, null,
|
||||
false);
|
||||
assertThat(readItemNamesFromResponse(response), hasSize(1));
|
||||
|
||||
itemResource.removeTag("Switch", "MyTag");
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "MyTag", null, false, null);
|
||||
response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "MyTag", null, false, null,
|
||||
false);
|
||||
assertThat(readItemNamesFromResponse(response), hasSize(0));
|
||||
}
|
||||
|
||||
@@ -192,8 +201,8 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
|
||||
public void shouldIncludeRequestedFieldsOnly() throws Exception {
|
||||
managedItemProvider.add(new SwitchItem("Switch"));
|
||||
itemResource.addTag("Switch", "MyTag");
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, null, null, "MyTag", null, false,
|
||||
"type,name");
|
||||
Response response = itemResource.getItems(uriInfoMock, httpHeadersMock, request, null, null, "MyTag", null,
|
||||
false, "type,name", false);
|
||||
|
||||
JsonElement result = JsonParser
|
||||
.parseString(new String(((InputStream) response.getEntity()).readAllBytes(), StandardCharsets.UTF_8));
|
||||
|
||||
Reference in New Issue
Block a user