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

Use Accept-Language header for locale in ConfigurableServiceResource #2602

Merged
merged 1 commit into from
Dec 10, 2021
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,13 +20,15 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

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;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
Expand All @@ -46,8 +48,8 @@
import org.openhab.core.config.core.ConfigurableServiceUtil;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.i18n.I18nUtil;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.openhab.core.io.rest.core.config.ConfigurationService;
Expand Down Expand Up @@ -109,28 +111,30 @@ public class ConfigurableServiceResource implements RESTResource {
private final ConfigDescriptionRegistry configDescRegistry;
private final ConfigurationService configurationService;
private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;
private final LocaleService localeService;

@Activate
public ConfigurableServiceResource( //
final BundleContext bundleContext, //
final @Reference ConfigurationService configurationService, //
final @Reference ConfigDescriptionRegistry configDescRegistry, //
final @Reference TranslationProvider translationProvider, //
final @Reference LocaleProvider localeProvider) {
final @Reference LocaleService localeService) {
this.bundleContext = bundleContext;
this.configDescRegistry = configDescRegistry;
this.configurationService = configurationService;
this.i18nProvider = translationProvider;
this.localeProvider = localeProvider;
this.localeService = localeService;
}

@GET
@Produces({ MediaType.APPLICATION_JSON })
@Operation(operationId = "getServices", summary = "Get all configurable services.", responses = {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ConfigurableServiceDTO.class)))) })
public List<ConfigurableServiceDTO> getAll() {
return getConfigurableServices();
public List<ConfigurableServiceDTO> getAll(
@HeaderParam("Accept-Language") @Parameter(description = "language") @Nullable String language) {
Locale locale = localeService.getLocale(language);
return getConfigurableServices(locale);
}

@GET
Expand All @@ -139,22 +143,25 @@ public List<ConfigurableServiceDTO> getAll() {
@Operation(operationId = "getServicesById", summary = "Get configurable service for given service ID.", responses = {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ConfigurableServiceDTO.class))),
@ApiResponse(responseCode = "404", description = "Not found") })
public Response getById(@PathParam("serviceId") @Parameter(description = "service ID") String serviceId) {
ConfigurableServiceDTO configurableService = getServiceById(serviceId);
public Response getById(
@HeaderParam("Accept-Language") @Parameter(description = "language") @Nullable String language,
@PathParam("serviceId") @Parameter(description = "service ID") String serviceId) {
Locale locale = localeService.getLocale(language);
ConfigurableServiceDTO configurableService = getServiceById(serviceId, locale);
if (configurableService != null) {
return Response.ok(configurableService).build();
} else {
return Response.status(404).build();
}
}

private @Nullable ConfigurableServiceDTO getServiceById(String serviceId) {
ConfigurableServiceDTO multiService = getMultiConfigServiceById(serviceId);
private @Nullable ConfigurableServiceDTO getServiceById(String serviceId, Locale locale) {
ConfigurableServiceDTO multiService = getMultiConfigServiceById(serviceId, locale);
if (multiService != null) {
return multiService;
}

List<ConfigurableServiceDTO> configurableServices = getConfigurableServices();
List<ConfigurableServiceDTO> configurableServices = getConfigurableServices(locale);
for (ConfigurableServiceDTO configurableService : configurableServices) {
if (configurableService.id.equals(serviceId)) {
return configurableService;
Expand All @@ -163,10 +170,10 @@ public Response getById(@PathParam("serviceId") @Parameter(description = "servic
return null;
}

private @Nullable ConfigurableServiceDTO getMultiConfigServiceById(String serviceId) {
private @Nullable ConfigurableServiceDTO getMultiConfigServiceById(String serviceId, Locale locale) {
String filter = "(&(" + Constants.SERVICE_PID + "=" + serviceId + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID
+ "=*))";
List<ConfigurableServiceDTO> services = getServicesByFilter(filter);
List<ConfigurableServiceDTO> services = getServicesByFilter(filter, locale);
if (services.size() == 1) {
return services.get(0);
}
Expand All @@ -179,13 +186,15 @@ public Response getById(@PathParam("serviceId") @Parameter(description = "servic
@Operation(operationId = "getServiceContext", summary = "Get existing multiple context service configurations for the given factory PID.", responses = {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ConfigurableServiceDTO.class)))) })
public List<ConfigurableServiceDTO> getMultiConfigServicesByFactoryPid(
@HeaderParam("Accept-Language") @Parameter(description = "language") @Nullable String language,
@PathParam("serviceId") @Parameter(description = "service ID") String serviceId) {
return collectServicesById(serviceId);
Locale locale = localeService.getLocale(language);
return collectServicesById(serviceId, locale);
}

private List<ConfigurableServiceDTO> collectServicesById(String serviceId) {
private List<ConfigurableServiceDTO> collectServicesById(String serviceId, Locale locale) {
String filter = "(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + serviceId + ")";
return getServicesByFilter(filter);
return getServicesByFilter(filter, locale);
}

@GET
Expand Down Expand Up @@ -213,11 +222,15 @@ public Response getConfiguration(@PathParam("serviceId") @Parameter(description
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))),
@ApiResponse(responseCode = "204", description = "No old configuration"),
@ApiResponse(responseCode = "500", description = "Configuration can not be updated due to internal error") })
public Response updateConfiguration(@PathParam("serviceId") @Parameter(description = "service ID") String serviceId,
public Response updateConfiguration(
@HeaderParam("Accept-Language") @Parameter(description = "language") @Nullable String language,
@PathParam("serviceId") @Parameter(description = "service ID") String serviceId,
@Nullable Map<String, Object> configuration) {
Locale locale = localeService.getLocale(language);
try {
Configuration oldConfiguration = configurationService.get(serviceId);
configurationService.update(serviceId, new Configuration(normalizeConfiguration(configuration, serviceId)));
configurationService.update(serviceId,
new Configuration(normalizeConfiguration(configuration, serviceId, locale)));
return oldConfiguration != null ? Response.ok(oldConfiguration.getProperties()).build()
: Response.noContent().build();
} catch (IOException ex) {
Expand All @@ -227,12 +240,12 @@ public Response updateConfiguration(@PathParam("serviceId") @Parameter(descripti
}

private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
String serviceId) {
String serviceId, Locale locale) {
if (properties == null || properties.isEmpty()) {
return properties;
}

ConfigurableServiceDTO service = getServiceById(serviceId);
ConfigurableServiceDTO service = getServiceById(serviceId, locale);
if (service == null) {
return properties;
}
Expand Down Expand Up @@ -272,7 +285,7 @@ public Response deleteConfiguration(
}
}

private List<ConfigurableServiceDTO> getServicesByFilter(String filter) {
private List<ConfigurableServiceDTO> getServicesByFilter(String filter, Locale locale) {
List<ConfigurableServiceDTO> services = new ArrayList<>();
ServiceReference<?>[] serviceReferences = null;
try {
Expand All @@ -296,8 +309,7 @@ private List<ConfigurableServiceDTO> getServicesByFilter(String filter) {
String key = I18nUtil.stripConstantOr(defaultLabel,
() -> inferKey(configurableService.description_uri(), "label"));

String label = i18nProvider.getText(serviceReference.getBundle(), key, defaultLabel,
localeProvider.getLocale());
String label = i18nProvider.getText(serviceReference.getBundle(), key, defaultLabel, locale);

String category = configurableService.category();

Expand Down Expand Up @@ -335,11 +347,11 @@ private List<ConfigurableServiceDTO> getServicesByFilter(String filter) {
return configDescriptionURI;
}

private List<ConfigurableServiceDTO> getConfigurableServices() {
private List<ConfigurableServiceDTO> getConfigurableServices(Locale locale) {
List<ConfigurableServiceDTO> services = new ArrayList<>();

services.addAll(getServicesByFilter(ConfigurableServiceUtil.CONFIGURABLE_SERVICE_FILTER));
services.addAll(getServicesByFilter(ConfigurableServiceUtil.CONFIGURABLE_MULTI_CONFIG_SERVICE_FILTER));
services.addAll(getServicesByFilter(ConfigurableServiceUtil.CONFIGURABLE_SERVICE_FILTER, locale));
services.addAll(getServicesByFilter(ConfigurableServiceUtil.CONFIGURABLE_MULTI_CONFIG_SERVICE_FILTER, locale));

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public void setUp() throws Exception {

@Test
public void assertGetConfigurableServicesWorks() {
int num = configurableServiceResource.getAll().size();
int num = configurableServiceResource.getAll("en").size();

Hashtable<String, Object> properties = new Hashtable<>();
properties.put("service.pid", "pid");
Expand All @@ -87,7 +87,7 @@ public void assertGetConfigurableServicesWorks() {

registerService(mock(SomeServiceInterface.class), properties);

List<ConfigurableServiceDTO> configurableServices = configurableServiceResource.getAll();
List<ConfigurableServiceDTO> configurableServices = configurableServiceResource.getAll("en");
assertThat(configurableServices.size(), is(num + 1));

Optional<ConfigurableServiceDTO> optionalService = configurableServices.stream()
Expand All @@ -105,15 +105,15 @@ public void assertGetConfigurableServicesWorks() {

@Test
public void assertComponentNameFallbackWorks() {
int num = configurableServiceResource.getAll().size();
int num = configurableServiceResource.getAll("en").size();

Hashtable<String, Object> properties = new Hashtable<>();
properties.put("component.name", "component.name");
properties.put("service.config.description.uri", "someuri");

registerService(mock(SomeServiceInterface.class), properties);

List<ConfigurableServiceDTO> configurableServices = configurableServiceResource.getAll();
List<ConfigurableServiceDTO> configurableServices = configurableServiceResource.getAll("en");
assertThat(configurableServices.size(), is(num + 1));

Optional<ConfigurableServiceDTO> optionalService = configurableServices.stream()
Expand All @@ -135,15 +135,15 @@ public void assertConfigurationManagementWorks() {

Map<String, Object> newConfiguration = new HashMap<>();
newConfiguration.put("a", "b");
response = configurableServiceResource.updateConfiguration("id", newConfiguration);
response = configurableServiceResource.updateConfiguration("en", "id", newConfiguration);
assertThat(response.getStatus(), is(204));

response = configurableServiceResource.getConfiguration("id");
assertThat(response.getStatus(), is(200));
assertThat(((Map) response.getEntity()).get("a"), is(equalTo("b")));

newConfiguration.put("a", "c");
response = configurableServiceResource.updateConfiguration("id", newConfiguration);
response = configurableServiceResource.updateConfiguration("en", "id", newConfiguration);
assertThat(response.getStatus(), is(200));
assertThat(((Map) response.getEntity()).get("a"), is(equalTo("b")));

Expand Down