Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Allow managing persistence configurations and enable filters #2871

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Locale;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
Expand All @@ -33,6 +34,7 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -57,7 +59,12 @@
import org.openhab.core.persistence.PersistenceServiceRegistry;
import org.openhab.core.persistence.QueryablePersistenceService;
import org.openhab.core.persistence.dto.ItemHistoryDTO;
import org.openhab.core.persistence.dto.PersistenceServiceConfigurationDTO;
import org.openhab.core.persistence.dto.PersistenceServiceDTO;
import org.openhab.core.persistence.registry.ManagedPersistenceServiceConfigurationProvider;
import org.openhab.core.persistence.registry.PersistenceServiceConfiguration;
import org.openhab.core.persistence.registry.PersistenceServiceConfigurationDTOMapper;
import org.openhab.core.persistence.registry.PersistenceServiceConfigurationRegistry;
import org.openhab.core.types.State;
import org.openhab.core.types.TypeParser;
import org.osgi.service.component.annotations.Activate;
Expand Down Expand Up @@ -114,17 +121,23 @@ public class PersistenceResource implements RESTResource {
private final ItemRegistry itemRegistry;
private final LocaleService localeService;
private final PersistenceServiceRegistry persistenceServiceRegistry;
private final PersistenceServiceConfigurationRegistry persistenceServiceConfigurationRegistry;
private final ManagedPersistenceServiceConfigurationProvider managedPersistenceServiceConfigurationProvider;
private final TimeZoneProvider timeZoneProvider;

@Activate
public PersistenceResource( //
final @Reference ItemRegistry itemRegistry, //
final @Reference LocaleService localeService,
final @Reference PersistenceServiceRegistry persistenceServiceRegistry,
final @Reference PersistenceServiceConfigurationRegistry persistenceServiceConfigurationRegistry,
final @Reference ManagedPersistenceServiceConfigurationProvider managedPersistenceServiceConfigurationProvider,
final @Reference TimeZoneProvider timeZoneProvider) {
this.itemRegistry = itemRegistry;
this.localeService = localeService;
this.persistenceServiceRegistry = persistenceServiceRegistry;
this.persistenceServiceConfigurationRegistry = persistenceServiceConfigurationRegistry;
this.managedPersistenceServiceConfigurationProvider = managedPersistenceServiceConfigurationProvider;
this.timeZoneProvider = timeZoneProvider;
}

Expand All @@ -142,6 +155,96 @@ public Response httpGetPersistenceServices(@Context HttpHeaders headers,
return Response.ok(responseObject).build();
}

@GET
@RolesAllowed({ Role.ADMIN })
@Produces({ MediaType.APPLICATION_JSON })
@Path("{serviceId: [a-zA-Z0-9]+}")
@Operation(operationId = "getPersistenceServiceConfiguration", summary = "Gets a persistence service configuration.", security = {
@SecurityRequirement(name = "oauth2", scopes = { "admin" }) }, responses = {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = PersistenceServiceConfigurationDTO.class))),
@ApiResponse(responseCode = "404", description = "Service configuration not found.") })
public Response httpGetPersistenceServiceConfiguration(@Context HttpHeaders headers,
@Parameter(description = "Id of the persistence service.") @PathParam("serviceId") String serviceId) {
PersistenceServiceConfiguration configuration = persistenceServiceConfigurationRegistry.get(serviceId);

if (configuration != null) {
PersistenceServiceConfigurationDTO configurationDTO = PersistenceServiceConfigurationDTOMapper
.map(configuration);
configurationDTO.editable = managedPersistenceServiceConfigurationProvider.get(serviceId) != null;
return JSONResponse.createResponse(Status.OK, configurationDTO, null);
} else {
return Response.status(Status.NOT_FOUND).build();
}
}

@PUT
@RolesAllowed({ Role.ADMIN })
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Path("{serviceId: [a-zA-Z0-9]+}")
@Operation(operationId = "putPersistenceServiceConfiguration", summary = "Sets a persistence service configuration.", security = {
@SecurityRequirement(name = "oauth2", scopes = { "admin" }) }, responses = {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = PersistenceServiceConfigurationDTO.class))),
@ApiResponse(responseCode = "201", description = "PersistenceServiceConfiguration created."),
@ApiResponse(responseCode = "400", description = "Payload invalid."),
@ApiResponse(responseCode = "405", description = "PersistenceServiceConfiguration not editable.") })
public Response httpPutPersistenceServiceConfiguration(@Context UriInfo uriInfo, @Context HttpHeaders headers,
@Parameter(description = "Id of the persistence service.") @PathParam("serviceId") String serviceId,
@Parameter(description = "service configuration", required = true) @Nullable PersistenceServiceConfigurationDTO serviceConfigurationDTO) {
if (serviceConfigurationDTO == null) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, "Payload must not be null.");
}
if (!serviceId.equals(serviceConfigurationDTO.serviceId)) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, "serviceId in payload '"
+ serviceConfigurationDTO.serviceId + "' differs from serviceId in URL '" + serviceId + "'");
}

PersistenceServiceConfiguration persistenceServiceConfiguration;
try {
persistenceServiceConfiguration = PersistenceServiceConfigurationDTOMapper.map(serviceConfigurationDTO);
} catch (IllegalArgumentException e) {
logger.warn("Received HTTP PUT request at '{}' with an invalid payload: '{}'.", uriInfo.getPath(),
e.getMessage());
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
}

if (persistenceServiceConfigurationRegistry.get(serviceId) == null) {
managedPersistenceServiceConfigurationProvider.add(persistenceServiceConfiguration);
return JSONResponse.createResponse(Status.CREATED, serviceConfigurationDTO, null);
} else if (managedPersistenceServiceConfigurationProvider.get(serviceId) != null) {
// item already exists as a managed item, update it
managedPersistenceServiceConfigurationProvider.update(persistenceServiceConfiguration);
return JSONResponse.createResponse(Status.OK, serviceConfigurationDTO, null);
} else {
// Configuration exists but cannot be updated
logger.warn("Cannot update existing persistence service configuration '{}', because is not managed.",
serviceId);
return JSONResponse.createErrorResponse(Status.METHOD_NOT_ALLOWED,
"Cannot update non-managed persistence service configuration " + serviceId);
}
}

@DELETE
@RolesAllowed({ Role.ADMIN })
@Path("{serviceId: [a-zA-Z0-9]+}")
@Operation(operationId = "deletePersistenceServiceConfiguration", summary = "Deletes a persistence service configuration.", security = {
@SecurityRequirement(name = "oauth2", scopes = { "admin" }) }, responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Persistence service configuration not found."),
@ApiResponse(responseCode = "405", description = "Persistence service configuration not editable.") })
public Response httpDeletePersistenceServiceConfiguration(@Context UriInfo uriInfo, @Context HttpHeaders headers,
@Parameter(description = "Id of the persistence service.") @PathParam("serviceId") String serviceId) {
if (persistenceServiceConfigurationRegistry.get(serviceId) == null) {
return Response.status(Status.NOT_FOUND).build();
}

if (managedPersistenceServiceConfigurationProvider.remove(serviceId) == null) {
return Response.status(Status.METHOD_NOT_ALLOWED).build();
} else {
return Response.ok().build();
}
}

@GET
@RolesAllowed({ Role.ADMIN })
@Path("/items")
Expand Down Expand Up @@ -238,7 +341,7 @@ private Response getItemHistoryDTO(@Nullable String serviceId, String itemName,
protected @Nullable ItemHistoryDTO createDTO(@Nullable String serviceId, String itemName,
@Nullable String timeBegin, @Nullable String timeEnd, int pageNumber, int pageLength, boolean boundary) {
// If serviceId is null, then use the default service
PersistenceService service = null;
PersistenceService service;
String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId();
service = persistenceServiceRegistry.get(effectiveServiceId);

Expand Down Expand Up @@ -283,9 +386,9 @@ private Response getItemHistoryDTO(@Nullable String serviceId, String itemName,
}

Iterable<HistoricItem> result;
State state = null;
State state;

Long quantity = 0l;
long quantity = 0L;

ItemHistoryDTO dto = new ItemHistoryDTO();
dto.name = itemName;
Expand Down Expand Up @@ -363,7 +466,7 @@ private Response getItemHistoryDTO(@Nullable String serviceId, String itemName,
/**
* Gets a list of persistence services currently configured in the system
*
* @return list of persistence services as {@link ServiceBean}
* @return list of persistence services
*/
private List<PersistenceServiceDTO> getPersistenceServiceList(Locale locale) {
List<PersistenceServiceDTO> dtoList = new ArrayList<>();
Expand All @@ -389,7 +492,7 @@ private List<PersistenceServiceDTO> getPersistenceServiceList(Locale locale) {

private Response getServiceItemList(@Nullable String serviceId) {
// If serviceId is null, then use the default service
PersistenceService service = null;
PersistenceService service;
if (serviceId == null) {
service = persistenceServiceRegistry.getDefault();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.openhab.core.persistence.QueryablePersistenceService;
import org.openhab.core.persistence.dto.ItemHistoryDTO;
import org.openhab.core.persistence.dto.ItemHistoryDTO.HistoryDataBean;
import org.openhab.core.persistence.registry.ManagedPersistenceServiceConfigurationProvider;
import org.openhab.core.persistence.registry.PersistenceServiceConfigurationRegistry;
import org.openhab.core.types.State;

/**
Expand All @@ -58,11 +60,14 @@ public class PersistenceResourceTest {
private @Mock @NonNullByDefault({}) ItemRegistry itemRegistryMock;
private @Mock @NonNullByDefault({}) LocaleService localeServiceMock;
private @Mock @NonNullByDefault({}) PersistenceServiceRegistry persistenceServiceRegistryMock;
private @Mock @NonNullByDefault({}) PersistenceServiceConfigurationRegistry persistenceServiceConfigurationRegistryMock;
private @Mock @NonNullByDefault({}) ManagedPersistenceServiceConfigurationProvider managedPersistenceServiceConfigurationProviderMock;
private @Mock @NonNullByDefault({}) TimeZoneProvider timeZoneProviderMock;

@BeforeEach
public void beforeEach() {
pResource = new PersistenceResource(itemRegistryMock, localeServiceMock, persistenceServiceRegistryMock,
persistenceServiceConfigurationRegistryMock, managedPersistenceServiceConfigurationProviderMock,
timeZoneProviderMock);

int startValue = 2016;
Expand Down
2 changes: 2 additions & 0 deletions bundles/org.openhab.core.model.persistence/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Import-Package: \
org.openhab.core.persistence,\
org.openhab.core.persistence.config,\
org.openhab.core.persistence.strategy,\
org.openhab.core.persistence.filter,\
org.openhab.core.persistence.registry,\
org.openhab.core.types,\
org.openhab.core.model.core,\
com.google.common.*;version="14",\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ FilterDetails:
;

ThresholdFilter:
'>' value=DECIMAL percent?='%'
'>' value=DECIMAL unit=STRING
;

TimeFilter:
Expand Down
Loading