Add null annotations to REST resources (#1475)

Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
Wouter Born 2020-05-17 19:32:35 +02:00 committed by GitHub
parent 054ad6c48e
commit 84d9438737
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 744 additions and 1495 deletions

View File

@ -22,11 +22,9 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
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;
@ -45,10 +43,9 @@ import org.openhab.core.automation.type.TriggerType;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -82,28 +79,15 @@ public class ModuleTypeResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_MODULE_TYPES = "module-types";
private @NonNullByDefault({}) ModuleTypeRegistry moduleTypeRegistry;
private @NonNullByDefault({}) LocaleService localeService;
private final LocaleService localeService;
private final ModuleTypeRegistry moduleTypeRegistry;
@Context
private @NonNullByDefault({}) UriInfo uriInfo;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setModuleTypeRegistry(ModuleTypeRegistry moduleTypeRegistry) {
this.moduleTypeRegistry = moduleTypeRegistry;
}
protected void unsetModuleTypeRegistry(ModuleTypeRegistry moduleTypeRegistry) {
this.moduleTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
@Activate
public ModuleTypeResource( //
final @Reference LocaleService localeService, //
final @Reference ModuleTypeRegistry moduleTypeRegistry) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.moduleTypeRegistry = moduleTypeRegistry;
}
@GET
@ -112,8 +96,8 @@ public class ModuleTypeResource implements RESTResource {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ModuleTypeDTO.class, responseContainer = "List") })
public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@QueryParam("tags") @ApiParam(value = "tags for filtering", required = false) @Nullable String tagList,
@QueryParam("type") @ApiParam(value = "filtering by action, condition or trigger", required = false) @Nullable String type) {
@QueryParam("tags") @ApiParam(value = "tags for filtering") @Nullable String tagList,
@QueryParam("type") @ApiParam(value = "filtering by action, condition or trigger") @Nullable String type) {
final Locale locale = localeService.getLocale(language);
final String[] tags = tagList != null ? tagList.split(",") : new String[0];
final List<ModuleTypeDTO> modules = new ArrayList<>();
@ -137,7 +121,7 @@ public class ModuleTypeResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ModuleTypeDTO.class),
@ApiResponse(code = 404, message = "Module Type corresponding to the given UID does not found.") })
public Response getByUID(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@PathParam("moduleTypeUID") @ApiParam(value = "moduleTypeUID", required = true) String moduleTypeUID) {
@PathParam("moduleTypeUID") @ApiParam(value = "moduleTypeUID") String moduleTypeUID) {
Locale locale = localeService.getLocale(language);
final ModuleType moduleType = moduleTypeRegistry.get(moduleTypeUID, locale);
if (moduleType != null) {
@ -168,9 +152,4 @@ public class ModuleTypeResource implements RESTResource {
String.format("Cannot handle given module type class (%s)", moduleType.getClass()));
}
}
@Override
public boolean isSatisfied() {
return moduleTypeRegistry != null && localeService != null;
}
}

View File

@ -38,6 +38,8 @@ 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;
import org.openhab.core.auth.Role;
import org.openhab.core.automation.Action;
import org.openhab.core.automation.Condition;
@ -64,10 +66,9 @@ import org.openhab.core.config.core.Configuration;
import org.openhab.core.io.rest.JSONResponse;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -98,6 +99,7 @@ import io.swagger.annotations.ResponseHeader;
@Path(RuleResource.PATH_RULES)
@Api(RuleResource.PATH_RULES)
@RolesAllowed({ Role.ADMIN })
@NonNullByDefault
public class RuleResource implements RESTResource {
/** The URI path to this resource */
@ -105,28 +107,17 @@ public class RuleResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(RuleResource.class);
private RuleRegistry ruleRegistry;
private RuleManager ruleManager;
private final RuleManager ruleManager;
private final RuleRegistry ruleRegistry;
@Context
private UriInfo uriInfo;
private @Context @NonNullByDefault({}) UriInfo uriInfo;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setRuleRegistry(RuleRegistry ruleRegistry) {
this.ruleRegistry = ruleRegistry;
}
protected void unsetRuleRegistry(RuleRegistry ruleRegistry) {
this.ruleRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setRuleManager(RuleManager ruleManager) {
@Activate
public RuleResource( //
final @Reference RuleManager ruleManager, //
final @Reference RuleRegistry ruleRegistry) {
this.ruleManager = ruleManager;
}
protected void unsetRuleManager(RuleManager ruleManager) {
this.ruleManager = null;
this.ruleRegistry = ruleRegistry;
}
@GET
@ -134,12 +125,13 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Get available rules, optionally filtered by tags and/or prefix.", response = EnrichedRuleDTO.class, responseContainer = "Collection")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = EnrichedRuleDTO.class, responseContainer = "Collection") })
public Response get(@QueryParam("prefix") final String prefix, @QueryParam("tags") final List<String> tags) {
public Response get(@QueryParam("prefix") final @Nullable String prefix,
@QueryParam("tags") final @Nullable List<String> tags) {
// match all
Predicate<Rule> p = r -> true;
// prefix parameter has been used
if (null != prefix) {
if (prefix != null) {
// works also for null prefix
// (empty prefix used if searching for rules without prefix)
p = p.and(hasPrefix(prefix));
@ -185,7 +177,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the rule corresponding to the given UID.", response = EnrichedRuleDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = EnrichedRuleDTO.class),
@ApiResponse(code = 404, message = "Rule not found") })
public Response getByUID(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID) {
public Response getByUID(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
return Response.ok(EnrichedRuleDTOMapper.map(rule, ruleManager)).build();
@ -200,7 +192,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Removes an existing rule corresponding to the given UID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response remove(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID) {
public Response remove(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) {
Rule removedRule = ruleRegistry.remove(ruleUID);
if (removedRule == null) {
logger.info("Received HTTP DELETE request at '{}' for the unknown rule '{}'.", uriInfo.getPath(), ruleUID);
@ -216,7 +208,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Updates an existing rule corresponding to the given UID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response update(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
public Response update(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@ApiParam(value = "rule data", required = true) RuleDTO rule) throws IOException {
rule.uid = ruleUID;
final Rule oldRule = ruleRegistry.update(RuleDTOMapper.map(rule));
@ -235,7 +227,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the rule configuration values.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response getConfiguration(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID)
public Response getConfiguration(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID)
throws IOException {
Rule rule = ruleRegistry.get(ruleUID);
if (rule == null) {
@ -253,8 +245,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Sets the rule configuration values.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response updateConfiguration(
@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
public Response updateConfiguration(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@ApiParam(value = "config") Map<String, Object> configurationParameters) throws IOException {
Map<String, Object> config = ConfigUtil.normalizeTypes(configurationParameters);
Rule rule = ruleRegistry.get(ruleUID);
@ -275,7 +266,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Sets the rule enabled status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response enableRule(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
public Response enableRule(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@ApiParam(value = "enable", required = true) String enabled) throws IOException {
Rule rule = ruleRegistry.get(ruleUID);
if (rule == null) {
@ -295,8 +286,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Executes actions of the rule.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response runNow(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID)
throws IOException {
public Response runNow(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) throws IOException {
Rule rule = ruleRegistry.get(ruleUID);
if (rule == null) {
logger.info("Received HTTP PUT request for run now at '{}' for the unknown rule '{}'.", uriInfo.getPath(),
@ -315,7 +305,7 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = TriggerDTO.class, responseContainer = "List"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response getTriggers(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID) {
public Response getTriggers(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
return Response.ok(TriggerDTOMapper.map(rule.getTriggers())).build();
@ -331,7 +321,7 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ConditionDTO.class, responseContainer = "List"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response getConditions(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID) {
public Response getConditions(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
return Response.ok(ConditionDTOMapper.map(rule.getConditions())).build();
@ -347,7 +337,7 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ActionDTO.class, responseContainer = "List"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response getActions(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID) {
public Response getActions(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
return Response.ok(ActionDTOMapper.map(rule.getActions())).build();
@ -362,9 +352,9 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the rule's module corresponding to the given Category and ID.", response = ModuleDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ModuleDTO.class),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found or does not have a module with such Category and ID.") })
public Response getModuleById(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory,
@PathParam("id") @ApiParam(value = "id", required = true) String id) {
public Response getModuleById(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("id") @ApiParam(value = "id") String id) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
final ModuleDTO dto = getModuleDTO(rule, moduleCategory, id);
@ -381,9 +371,9 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the module's configuration.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found or does not have a module with such Category and ID.") })
public Response getModuleConfig(@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory,
@PathParam("id") @ApiParam(value = "id", required = true) String id) {
public Response getModuleConfig(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("id") @ApiParam(value = "id") String id) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
Module module = getModule(rule, moduleCategory, id);
@ -400,11 +390,10 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the module's configuration parameter.", response = String.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found or does not have a module with such Category and ID.") })
public Response getModuleConfigParam(
@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory,
@PathParam("id") @ApiParam(value = "id", required = true) String id,
@PathParam("param") @ApiParam(value = "param", required = true) String param) {
public Response getModuleConfigParam(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("id") @ApiParam(value = "id") String id,
@PathParam("param") @ApiParam(value = "param") String param) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
Module module = getModule(rule, moduleCategory, id);
@ -421,11 +410,10 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found or does not have a module with such Category and ID.") })
@Consumes(MediaType.TEXT_PLAIN)
public Response setModuleConfigParam(
@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory,
@PathParam("id") @ApiParam(value = "id", required = true) String id,
@PathParam("param") @ApiParam(value = "param", required = true) String param,
public Response setModuleConfigParam(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("id") @ApiParam(value = "id") String id,
@PathParam("param") @ApiParam(value = "param") String param,
@ApiParam(value = "value", required = true) String value) {
Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) {
@ -441,10 +429,7 @@ public class RuleResource implements RESTResource {
return Response.status(Status.NOT_FOUND).build();
}
protected <T extends Module> T getModuleById(final Collection<T> coll, final String id) {
if (coll == null) {
return null;
}
protected <T extends Module> @Nullable T getModuleById(final Collection<T> coll, final String id) {
for (final T module : coll) {
if (module.getId().equals(id)) {
return module;
@ -453,19 +438,19 @@ public class RuleResource implements RESTResource {
return null;
}
protected Trigger getTrigger(Rule rule, String id) {
protected @Nullable Trigger getTrigger(Rule rule, String id) {
return getModuleById(rule.getTriggers(), id);
}
protected Condition getCondition(Rule rule, String id) {
protected @Nullable Condition getCondition(Rule rule, String id) {
return getModuleById(rule.getConditions(), id);
}
protected Action getAction(Rule rule, String id) {
protected @Nullable Action getAction(Rule rule, String id) {
return getModuleById(rule.getActions(), id);
}
protected Module getModule(Rule rule, String moduleCategory, String id) {
protected @Nullable Module getModule(Rule rule, String moduleCategory, String id) {
if ("triggers".equals(moduleCategory)) {
return getTrigger(rule, id);
} else if ("conditions".equals(moduleCategory)) {
@ -477,7 +462,7 @@ public class RuleResource implements RESTResource {
}
}
protected ModuleDTO getModuleDTO(Rule rule, String moduleCategory, String id) {
protected @Nullable ModuleDTO getModuleDTO(Rule rule, String moduleCategory, String id) {
if ("triggers".equals(moduleCategory)) {
final Trigger trigger = getTrigger(rule, id);
return trigger == null ? null : TriggerDTOMapper.map(trigger);
@ -491,9 +476,4 @@ public class RuleResource implements RESTResource {
return null;
}
}
@Override
public boolean isSatisfied() {
return ruleRegistry != null && ruleManager != null;
}
}

View File

@ -21,14 +21,13 @@ import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
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.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.dto.RuleTemplateDTO;
import org.openhab.core.automation.dto.RuleTemplateDTOMapper;
import org.openhab.core.automation.template.RuleTemplate;
@ -37,10 +36,9 @@ import org.openhab.core.automation.template.TemplateRegistry;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -72,28 +70,15 @@ public class TemplateResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_TEMPLATES = "templates";
private @NonNullByDefault({}) TemplateRegistry<@NonNull RuleTemplate> templateRegistry;
private @NonNullByDefault({}) LocaleService localeService;
private final LocaleService localeService;
private final TemplateRegistry<@NonNull RuleTemplate> templateRegistry;
@Context
private @NonNullByDefault({}) UriInfo uriInfo;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setTemplateRegistry(TemplateRegistry<RuleTemplate> templateRegistry) {
this.templateRegistry = templateRegistry;
}
protected void unsetTemplateRegistry(TemplateRegistry<RuleTemplate> templateRegistry) {
this.templateRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
@Activate
public TemplateResource( //
final @Reference LocaleService localeService,
final @Reference TemplateRegistry<@NonNull RuleTemplate> templateRegistry) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.templateRegistry = templateRegistry;
}
@GET
@ -101,7 +86,7 @@ public class TemplateResource implements RESTResource {
@ApiOperation(value = "Get all available templates.", response = Template.class, responseContainer = "Collection")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = Template.class, responseContainer = "Collection") })
public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language) {
public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language) {
Locale locale = localeService.getLocale(language);
Collection<RuleTemplateDTO> result = templateRegistry.getAll(locale).stream()
.map(template -> RuleTemplateDTOMapper.map(template)).collect(Collectors.toList());
@ -114,8 +99,8 @@ public class TemplateResource implements RESTResource {
@ApiOperation(value = "Gets a template corresponding to the given UID.", response = Template.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = Template.class),
@ApiResponse(code = 404, message = "Template corresponding to the given UID does not found.") })
public Response getByUID(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language,
@PathParam("templateUID") @ApiParam(value = "templateUID", required = true) String templateUID) {
public Response getByUID(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@PathParam("templateUID") @ApiParam(value = "templateUID") String templateUID) {
Locale locale = localeService.getLocale(language);
RuleTemplate template = templateRegistry.get(templateUID, locale);
if (template != null) {
@ -124,9 +109,4 @@ public class TemplateResource implements RESTResource {
return Response.status(Status.NOT_FOUND).build();
}
}
@Override
public boolean isSatisfied() {
return templateRegistry != null && localeService != null;
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.core.automation.dto;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.template.RuleTemplate;
import org.openhab.core.config.core.dto.ConfigDescriptionDTOMapper;
@ -20,6 +21,7 @@ import org.openhab.core.config.core.dto.ConfigDescriptionDTOMapper;
*
* @author Ana Dimova - Initial contribution
*/
@NonNullByDefault
public class RuleTemplateDTOMapper {
public static RuleTemplateDTO map(final RuleTemplate template) {

View File

@ -61,7 +61,7 @@ public class Configuration {
*
* @param properties the properties the configuration should be filled. If null, an empty configuration is created.
*/
public Configuration(Map<String, Object> properties) {
public Configuration(@Nullable Map<String, Object> properties) {
this(properties == null ? emptyMap() : properties, false);
}
@ -103,7 +103,7 @@ public class Configuration {
return properties.get(key);
}
public Object put(String key, Object value) {
public Object put(String key, @Nullable Object value) {
return properties.put(key, ConfigUtil.normalizeType(value, null));
}
@ -150,7 +150,7 @@ public class Configuration {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
return (obj instanceof Configuration) && this.properties.equals(((Configuration) obj).properties);
}

View File

@ -19,6 +19,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.auth.Role;
import org.openhab.core.id.InstanceUUID;
import org.openhab.core.io.rest.RESTConstants;
@ -47,6 +48,7 @@ import io.swagger.annotations.ApiResponses;
@Path(UUIDResource.PATH_UUID)
@Api(UUIDResource.PATH_UUID)
@RolesAllowed({ Role.ADMIN })
@NonNullByDefault
public class UUIDResource implements RESTResource {
public static final String PATH_UUID = "uuid";

View File

@ -37,10 +37,9 @@ import org.openhab.core.io.rest.JSONResponse;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -70,29 +69,20 @@ import io.swagger.annotations.ApiResponses;
@NonNullByDefault
public class AudioResource implements RESTResource {
static final String PATH_AUDIO = "audio";
/** The URI path to this resource */
public static final String PATH_AUDIO = "audio";
private @Nullable AudioManager audioManager;
private @Nullable LocaleService localeService;
private final AudioManager audioManager;
private final LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
public void setAudioManager(AudioManager audioManager) {
@Activate
public AudioResource( //
final @Reference AudioManager audioManager, //
final @Reference LocaleService localeService) {
this.audioManager = audioManager;
}
public void unsetAudioManager(AudioManager audioManager) {
this.audioManager = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@GET
@Path("/sources")
@Produces(MediaType.APPLICATION_JSON)
@ -158,9 +148,4 @@ public class AudioResource implements RESTResource {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Sink not found");
}
}
@Override
public boolean isSatisfied() {
return audioManager != null && localeService != null;
}
}

View File

@ -40,6 +40,7 @@ import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.jose4j.base64url.Base64Url;
import org.openhab.core.auth.ManagedUser;
import org.openhab.core.auth.PendingToken;
@ -79,6 +80,7 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired
@Path(TokenResource.PATH_AUTH)
@Api(TokenResource.PATH_AUTH)
@NonNullByDefault
public class TokenResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(TokenResource.class);
@ -91,11 +93,10 @@ public class TokenResource implements RESTResource {
/** The default lifetime of tokens in minutes before they expire */
public static final int TOKEN_LIFETIME = 60;
@Context
private UriInfo uriInfo;
private @Context @NonNullByDefault({}) UriInfo uriInfo;
private UserRegistry userRegistry;
private JwtHelper jwtHelper;
private final UserRegistry userRegistry;
private final JwtHelper jwtHelper;
@Activate
public TokenResource(final @Reference UserRegistry userRegistry, final @Reference JwtHelper jwtHelper) {

View File

@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.ConfigConstants;
import org.openhab.core.config.core.Configuration;
import org.osgi.framework.Constants;
@ -52,7 +53,7 @@ public class ConfigurationService {
* @return config or null if no config with the given config id exists
* @throws IOException if configuration can not be read
*/
public Configuration get(String configId) throws IOException {
public @Nullable Configuration get(String configId) throws IOException {
org.osgi.service.cm.Configuration configuration = configurationAdmin.getConfiguration(configId, null);
Dictionary<String, Object> properties = configuration.getProperties();
return toConfiguration(properties);
@ -161,7 +162,7 @@ public class ConfigurationService {
return oldConfiguration;
}
private Configuration toConfiguration(Dictionary<String, Object> dictionary) {
private @Nullable Configuration toConfiguration(Dictionary<String, Object> dictionary) {
if (dictionary == null) {
return null;
}

View File

@ -27,7 +27,7 @@ import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsExtension;
/**
* Trap exceptions.
*
* @author Markus Rathgeb - Migrated to JAX-RS Whiteboard Specification
* @author Markus Rathgeb - Initial contribution
*/
@Component
@JaxrsExtension

View File

@ -27,13 +27,13 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
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;
import org.openhab.core.auth.Role;
import org.openhab.core.binding.BindingInfo;
import org.openhab.core.binding.BindingInfoRegistry;
@ -47,10 +47,9 @@ import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.openhab.core.io.rest.Stream2JSONInputStream;
import org.openhab.core.io.rest.core.config.ConfigurationService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -83,6 +82,7 @@ import io.swagger.annotations.ApiResponses;
@Path(BindingResource.PATH_BINDINGS)
@RolesAllowed({ Role.ADMIN })
@Api(BindingResource.PATH_BINDINGS)
@NonNullByDefault
public class BindingResource implements RESTResource {
/** The URI path to this resource */
@ -90,40 +90,30 @@ public class BindingResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(BindingResource.class);
private ConfigurationService configurationService;
private ConfigDescriptionRegistry configDescRegistry;
private final BindingInfoRegistry bindingInfoRegistry;
private final ConfigurationService configurationService;
private final ConfigDescriptionRegistry configDescRegistry;
private final LocaleService localeService;
private BindingInfoRegistry bindingInfoRegistry;
private LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setBindingInfoRegistry(BindingInfoRegistry bindingInfoRegistry) {
@Activate
public BindingResource( //
final @Reference BindingInfoRegistry bindingInfoRegistry,
final @Reference ConfigurationService configurationService,
final @Reference ConfigDescriptionRegistry configDescRegistry,
final @Reference LocaleService localeService) {
this.bindingInfoRegistry = bindingInfoRegistry;
}
protected void unsetBindingInfoRegistry(BindingInfoRegistry bindingInfoRegistry) {
this.bindingInfoRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.configurationService = configurationService;
this.configDescRegistry = configDescRegistry;
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@Context
UriInfo uriInfo;
@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all bindings.", response = BindingInfoDTO.class, responseContainer = "Set")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = BindingInfoDTO.class, responseContainer = "Set") })
public Response getAll(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language) {
public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
final Locale locale = localeService.getLocale(language);
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(locale);
@ -137,8 +127,7 @@ public class BindingResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Binding does not exist"),
@ApiResponse(code = 500, message = "Configuration can not be read due to internal error") })
public Response getConfiguration(
@PathParam("bindingId") @ApiParam(value = "service ID", required = true) String bindingId) {
public Response getConfiguration(@PathParam("bindingId") @ApiParam(value = "service ID") String bindingId) {
try {
String configId = getConfigId(bindingId);
if (configId == null) {
@ -164,9 +153,8 @@ public class BindingResource implements RESTResource {
@ApiResponse(code = 204, message = "No old configuration"),
@ApiResponse(code = 404, message = "Binding does not exist"),
@ApiResponse(code = 500, message = "Configuration can not be updated due to internal error") })
public Response updateConfiguration(
@PathParam("bindingId") @ApiParam(value = "service ID", required = true) String bindingId,
Map<String, Object> configuration) {
public Response updateConfiguration(@PathParam("bindingId") @ApiParam(value = "service ID") String bindingId,
@Nullable Map<String, Object> configuration) {
try {
String configId = getConfigId(bindingId);
if (configId == null) {
@ -184,7 +172,8 @@ public class BindingResource implements RESTResource {
}
}
private Map<String, Object> normalizeConfiguration(Map<String, Object> properties, String bindingId) {
private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
String bindingId) {
if (properties == null || properties.isEmpty()) {
return properties;
}
@ -202,7 +191,7 @@ public class BindingResource implements RESTResource {
return ConfigUtil.normalizeTypes(properties, Collections.singletonList(configDesc));
}
private String getConfigId(String bindingId) {
private @Nullable String getConfigId(String bindingId) {
BindingInfo bindingInfo = this.bindingInfoRegistry.getBindingInfo(bindingId);
if (bindingInfo != null) {
return bindingInfo.getServiceId();
@ -216,28 +205,4 @@ public class BindingResource implements RESTResource {
return new BindingInfoDTO(bindingInfo.getUID(), bindingInfo.getName(), bindingInfo.getAuthor(),
bindingInfo.getDescription(), configDescriptionURI != null ? configDescriptionURI.toString() : null);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
protected void unsetConfigurationService(ConfigurationService configurationService) {
this.configurationService = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescRegistry = null;
}
@Override
public boolean isSatisfied() {
return configurationService != null && configDescRegistry != null && bindingInfoRegistry != null
&& localeService != null;
}
}

View File

@ -32,6 +32,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigDescription;
@ -52,10 +53,9 @@ import org.openhab.core.thing.type.ChannelKind;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -84,52 +84,27 @@ import io.swagger.annotations.ApiResponses;
@Path(ChannelTypeResource.PATH_CHANNEL_TYPES)
@RolesAllowed({ Role.ADMIN })
@Api(ChannelTypeResource.PATH_CHANNEL_TYPES)
@NonNullByDefault
public class ChannelTypeResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_CHANNEL_TYPES = "channel-types";
private ChannelTypeRegistry channelTypeRegistry;
private ConfigDescriptionRegistry configDescriptionRegistry;
private final ChannelTypeRegistry channelTypeRegistry;
private final ConfigDescriptionRegistry configDescriptionRegistry;
private final LocaleService localeService;
private final ProfileTypeRegistry profileTypeRegistry;
private ProfileTypeRegistry profileTypeRegistry;
private LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
@Activate
public ChannelTypeResource( //
final @Reference ChannelTypeRegistry channelTypeRegistry,
final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
final @Reference LocaleService localeService, //
final @Reference ProfileTypeRegistry profileTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
}
protected void unsetChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
this.channelTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setProfileTypeRegistry(ProfileTypeRegistry profileTypeRegistry) {
this.profileTypeRegistry = profileTypeRegistry;
}
protected void unsetProfileTypeRegistry(ProfileTypeRegistry profileTypeRegistry) {
this.profileTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.profileTypeRegistry = profileTypeRegistry;
}
@GET
@ -137,8 +112,8 @@ public class ChannelTypeResource implements RESTResource {
@ApiOperation(value = "Gets all available channel types.", response = ChannelTypeDTO.class, responseContainer = "Set")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ChannelTypeDTO.class, responseContainer = "Set"))
public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language,
@QueryParam("prefixes") @ApiParam(value = "filter UIDs by prefix (multiple comma-separated prefixes allowed, for example: 'system,mqtt')", required = false) @Nullable String prefixes) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("prefixes") @ApiParam(value = "filter UIDs by prefix (multiple comma-separated prefixes allowed, for example: 'system,mqtt')") @Nullable String prefixes) {
Locale locale = localeService.getLocale(language);
Stream<ChannelTypeDTO> channelStream = channelTypeRegistry.getChannelTypes(locale).stream()
@ -163,7 +138,7 @@ public class ChannelTypeResource implements RESTResource {
@ApiResponse(code = 200, message = "Channel type with provided channelTypeUID does not exist.", response = ChannelTypeDTO.class),
@ApiResponse(code = 404, message = "No content") })
public Response getByUID(@PathParam("channelTypeUID") @ApiParam(value = "channelTypeUID") String channelTypeUID,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
Locale locale = localeService.getLocale(language);
ChannelType channelType = channelTypeRegistry.getChannelType(new ChannelTypeUID(channelTypeUID), locale);
if (channelType != null) {
@ -235,10 +210,4 @@ public class ChannelTypeResource implements RESTResource {
parameterGroups, channelType.getState(), channelType.getTags(), channelType.isAdvanced(),
channelType.getCommandDescription());
}
@Override
public boolean isSatisfied() {
return channelTypeRegistry != null && configDescriptionRegistry != null && profileTypeRegistry != null
&& localeService != null;
}
}

View File

@ -40,10 +40,9 @@ import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.openhab.core.io.rest.Stream2JSONInputStream;
import org.openhab.core.io.rest.core.config.EnrichedConfigDescriptionDTOMapper;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -78,26 +77,23 @@ public class ConfigDescriptionResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_CONFIG_DESCRIPTIONS = "config-descriptions";
private @NonNullByDefault({}) ConfigDescriptionRegistry configDescriptionRegistry;
private final ConfigDescriptionRegistry configDescriptionRegistry;
private final LocaleService localeService;
private @NonNullByDefault({}) LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
@Activate
public ConfigDescriptionResource( //
final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
final @Reference LocaleService localeService) {
this.configDescriptionRegistry = configDescriptionRegistry;
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets all available config descriptions.", response = ConfigDescriptionDTO.class, responseContainer = "List")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ConfigDescriptionDTO.class, responseContainer = "List"))
public Response getAll(
@HeaderParam("Accept-Language") @ApiParam(value = "Accept-Language") @Nullable String language, //
@QueryParam("scheme") @ApiParam(value = "scheme filter", required = false) @Nullable String scheme) {
public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language, //
@QueryParam("scheme") @ApiParam(value = "scheme filter") @Nullable String scheme) {
Locale locale = localeService.getLocale(language);
Collection<ConfigDescription> configDescriptions = configDescriptionRegistry.getConfigDescriptions(locale);
return Response.ok(new Stream2JSONInputStream(configDescriptions.stream().filter(configDescription -> {
@ -111,8 +107,7 @@ public class ConfigDescriptionResource implements RESTResource {
@ApiOperation(value = "Gets a config description by URI.", response = ConfigDescriptionDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ConfigDescriptionDTO.class),
@ApiResponse(code = 400, message = "Invalid URI syntax"), @ApiResponse(code = 404, message = "Not found") })
public Response getByURI(
@HeaderParam("Accept-Language") @ApiParam(value = "Accept-Language") @Nullable String language,
public Response getByURI(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@PathParam("uri") @ApiParam(value = "uri") String uri) {
Locale locale = localeService.getLocale(language);
URI uriObject = UriBuilder.fromPath(uri).build();
@ -121,18 +116,4 @@ public class ConfigDescriptionResource implements RESTResource {
? Response.ok(EnrichedConfigDescriptionDTOMapper.map(configDescription)).build()
: JSONResponse.createErrorResponse(Status.NOT_FOUND, "Configuration not found: " + uri);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = null;
}
@Override
public boolean isSatisfied() {
return configDescriptionRegistry != null && localeService != null;
}
}

View File

@ -21,20 +21,19 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
import org.openhab.core.config.discovery.ScanListener;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -68,6 +67,7 @@ import io.swagger.annotations.ApiResponses;
@Path(DiscoveryResource.PATH_DISCOVERY)
@RolesAllowed({ Role.ADMIN })
@Api(DiscoveryResource.PATH_DISCOVERY)
@NonNullByDefault
public class DiscoveryResource implements RESTResource {
/** The URI path to this resource */
@ -75,20 +75,13 @@ public class DiscoveryResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(DiscoveryResource.class);
private DiscoveryServiceRegistry discoveryServiceRegistry;
private final DiscoveryServiceRegistry discoveryServiceRegistry;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setDiscoveryServiceRegistry(DiscoveryServiceRegistry discoveryServiceRegistry) {
@Activate
public DiscoveryResource(final @Reference DiscoveryServiceRegistry discoveryServiceRegistry) {
this.discoveryServiceRegistry = discoveryServiceRegistry;
}
protected void unsetDiscoveryServiceRegistry(DiscoveryServiceRegistry discoveryServiceRegistry) {
this.discoveryServiceRegistry = null;
}
@Context
private UriInfo uriInfo;
@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets all bindings that support discovery.", response = String.class, responseContainer = "Set")
@ -107,9 +100,8 @@ public class DiscoveryResource implements RESTResource {
public Response scan(@PathParam("bindingId") @ApiParam(value = "bindingId") final String bindingId) {
discoveryServiceRegistry.startScan(bindingId, new ScanListener() {
@Override
public void onErrorOccurred(Exception exception) {
logger.error("Error occurred while scanning for binding '{}': {}", bindingId, exception.getMessage(),
exception);
public void onErrorOccurred(@Nullable Exception exception) {
logger.error("Error occurred while scanning for binding '{}'", bindingId, exception);
}
@Override
@ -120,9 +112,4 @@ public class DiscoveryResource implements RESTResource {
return Response.ok(discoveryServiceRegistry.getMaxScanTimeout(bindingId)).build();
}
@Override
public boolean isSatisfied() {
return discoveryServiceRegistry != null;
}
}

View File

@ -23,13 +23,13 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
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;
import org.openhab.core.auth.Role;
import org.openhab.core.config.discovery.DiscoveryResultFlag;
import org.openhab.core.config.discovery.dto.DiscoveryResultDTO;
@ -41,10 +41,9 @@ import org.openhab.core.io.rest.RESTResource;
import org.openhab.core.io.rest.Stream2JSONInputStream;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -78,26 +77,20 @@ import io.swagger.annotations.ApiResponses;
@Path(InboxResource.PATH_INBOX)
@RolesAllowed({ Role.ADMIN })
@Api(InboxResource.PATH_INBOX)
@NonNullByDefault
public class InboxResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(InboxResource.class);
/** The URI path to this resource */
public static final String PATH_INBOX = "inbox";
private Inbox inbox;
private final Inbox inbox;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setInbox(Inbox inbox) {
@Activate
public InboxResource(final @Reference Inbox inbox) {
this.inbox = inbox;
}
protected void unsetInbox(Inbox inbox) {
this.inbox = null;
}
@Context
private UriInfo uriInfo;
@POST
@Path("/{thingUID}/approve")
@Consumes(MediaType.TEXT_PLAIN)
@ -105,9 +98,10 @@ public class InboxResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Thing unable to be approved."),
@ApiResponse(code = 409, message = "No binding found that supports this thing.") })
public Response approve(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@PathParam("thingUID") @ApiParam(value = "thingUID", required = true) String thingUID,
@ApiParam(value = "thing label") String label) {
public Response approve(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@ApiParam(value = "thing label") @Nullable String label) {
ThingUID thingUIDObject = new ThingUID(thingUID);
String notEmptyLabel = label != null && !label.isEmpty() ? label : null;
Thing thing = null;
@ -131,7 +125,7 @@ public class InboxResource implements RESTResource {
@ApiOperation(value = "Removes the discovery result from the inbox.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Discovery result not found in the inbox.") })
public Response delete(@PathParam("thingUID") @ApiParam(value = "thingUID", required = true) String thingUID) {
public Response delete(@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID) {
if (inbox.remove(new ThingUID(thingUID))) {
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} else {
@ -152,7 +146,7 @@ public class InboxResource implements RESTResource {
@Path("/{thingUID}/ignore")
@ApiOperation(value = "Flags a discovery result as ignored for further processing.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response ignore(@PathParam("thingUID") @ApiParam(value = "thingUID", required = true) String thingUID) {
public Response ignore(@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID) {
inbox.setFlag(new ThingUID(thingUID), DiscoveryResultFlag.IGNORED);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
}
@ -161,13 +155,8 @@ public class InboxResource implements RESTResource {
@Path("/{thingUID}/unignore")
@ApiOperation(value = "Removes ignore flag from a discovery result.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response unignore(@PathParam("thingUID") @ApiParam(value = "thingUID", required = true) String thingUID) {
public Response unignore(@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID) {
inbox.setFlag(new ThingUID(thingUID), DiscoveryResultFlag.NEW);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
}
@Override
public boolean isSatisfied() {
return inbox != null;
}
}

View File

@ -35,6 +35,8 @@ 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;
import org.openhab.core.auth.Role;
import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.events.Event;
@ -48,6 +50,7 @@ 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.Stream2JSONInputStream;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
@ -81,6 +84,7 @@ import io.swagger.annotations.ApiResponses;
@Path(ExtensionResource.PATH_EXTENSIONS)
@RolesAllowed({ Role.ADMIN })
@Api(ExtensionResource.PATH_EXTENSIONS)
@NonNullByDefault
public class ExtensionResource implements RESTResource {
private static final String THREAD_POOL_NAME = "extensionService";
@ -88,12 +92,18 @@ public class ExtensionResource implements RESTResource {
public static final String PATH_EXTENSIONS = "extensions";
private final Logger logger = LoggerFactory.getLogger(ExtensionResource.class);
private final Set<ExtensionService> extensionServices = new CopyOnWriteArraySet<>();
private final EventPublisher eventPublisher;
private final LocaleService localeService;
private EventPublisher eventPublisher;
private @Context @NonNullByDefault({}) UriInfo uriInfo;
private LocaleService localeService;
@Activate
public ExtensionResource(final @Reference EventPublisher eventPublisher,
final @Reference LocaleService localeService) {
this.eventPublisher = eventPublisher;
this.localeService = localeService;
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addExtensionService(ExtensionService featureService) {
@ -104,32 +114,12 @@ public class ExtensionResource implements RESTResource {
this.extensionServices.remove(featureService);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
protected void unsetEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@Context
UriInfo uriInfo;
@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all extensions.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class) })
public Response getExtensions(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language) {
public Response getExtensions(
@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language) {
logger.debug("Received HTTP GET request at '{}'", uriInfo.getPath());
Locale locale = localeService.getLocale(language);
return Response.ok(new Stream2JSONInputStream(getAllExtensions(locale))).build();
@ -140,7 +130,7 @@ public class ExtensionResource implements RESTResource {
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all extension types.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class) })
public Response getTypes(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language) {
public Response getTypes(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language) {
logger.debug("Received HTTP GET request at '{}'", uriInfo.getPath());
Locale locale = localeService.getLocale(language);
Stream<ExtensionType> extensionTypeStream = getAllExtensionTypes(locale).stream().distinct();
@ -153,8 +143,8 @@ public class ExtensionResource implements RESTResource {
@ApiOperation(value = "Get extension with given ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Not found") })
public Response getById(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language,
@PathParam("extensionId") @ApiParam(value = "extension ID", required = true) String extensionId) {
public Response getById(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@PathParam("extensionId") @ApiParam(value = "extension ID") String extensionId) {
logger.debug("Received HTTP GET request at '{}'.", uriInfo.getPath());
Locale locale = localeService.getLocale(language);
ExtensionService extensionService = getExtensionService(extensionId);
@ -171,7 +161,7 @@ public class ExtensionResource implements RESTResource {
@ApiOperation(value = "Installs the extension with the given ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response installExtension(
final @PathParam("extensionId") @ApiParam(value = "extension ID", required = true) String extensionId) {
final @PathParam("extensionId") @ApiParam(value = "extension ID") String extensionId) {
ThreadPoolManager.getPool(THREAD_POOL_NAME).submit(() -> {
try {
ExtensionService extensionService = getExtensionService(extensionId);
@ -190,7 +180,7 @@ public class ExtensionResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 400, message = "The given URL is malformed or not valid.") })
public Response installExtensionByURL(
final @PathParam("url") @ApiParam(value = "extension install URL", required = true) String url) {
final @PathParam("url") @ApiParam(value = "extension install URL") String url) {
try {
URI extensionURI = new URI(url);
String extensionId = getExtensionId(extensionURI);
@ -208,7 +198,7 @@ public class ExtensionResource implements RESTResource {
@ApiOperation(value = "Uninstalls the extension with the given ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response uninstallExtension(
final @PathParam("extensionId") @ApiParam(value = "extension ID", required = true) String extensionId) {
final @PathParam("extensionId") @ApiParam(value = "extension ID") String extensionId) {
ThreadPoolManager.getPool(THREAD_POOL_NAME).submit(() -> {
try {
ExtensionService extensionService = getExtensionService(extensionId);
@ -222,15 +212,8 @@ public class ExtensionResource implements RESTResource {
}
private void postFailureEvent(String extensionId, String msg) {
if (eventPublisher != null) {
Event event = ExtensionEventFactory.createExtensionFailureEvent(extensionId, msg);
eventPublisher.post(event);
}
}
@Override
public boolean isSatisfied() {
return !extensionServices.isEmpty() && localeService != null;
Event event = ExtensionEventFactory.createExtensionFailureEvent(extensionId, msg);
eventPublisher.post(event);
}
private Stream<Extension> getAllExtensions(Locale locale) {

View File

@ -79,10 +79,9 @@ import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.TypeParser;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -153,85 +152,33 @@ public class ItemResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(ItemResource.class);
private @NonNullByDefault({}) ItemRegistry itemRegistry;
private @NonNullByDefault({}) MetadataRegistry metadataRegistry;
private @NonNullByDefault({}) EventPublisher eventPublisher;
private @NonNullByDefault({}) ManagedItemProvider managedItemProvider;
private @NonNullByDefault({}) DTOMapper dtoMapper;
private @NonNullByDefault({}) MetadataSelectorMatcher metadataSelectorMatcher;
private @NonNullByDefault({}) ItemBuilderFactory itemBuilderFactory;
private @NonNullByDefault({}) LocaleService localeService;
private final DTOMapper dtoMapper;
private final EventPublisher eventPublisher;
private final ItemBuilderFactory itemBuilderFactory;
private final ItemRegistry itemRegistry;
private final LocaleService localeService;
private final ManagedItemProvider managedItemProvider;
private final MetadataRegistry metadataRegistry;
private final MetadataSelectorMatcher metadataSelectorMatcher;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = itemRegistry;
}
protected void unsetItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setMetadataRegistry(MetadataRegistry metadataRegistry) {
this.metadataRegistry = metadataRegistry;
}
protected void unsetMetadataRegistry(MetadataRegistry metadataRegistry) {
this.metadataRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setEventPublisher(EventPublisher eventPublisher) {
@Activate
public ItemResource(//
final @Reference DTOMapper dtoMapper, //
final @Reference EventPublisher eventPublisher, //
final @Reference ItemBuilderFactory itemBuilderFactory, //
final @Reference ItemRegistry itemRegistry, //
final @Reference LocaleService localeService, //
final @Reference ManagedItemProvider managedItemProvider,
final @Reference MetadataRegistry metadataRegistry,
final @Reference MetadataSelectorMatcher metadataSelectorMatcher) {
this.dtoMapper = dtoMapper;
this.eventPublisher = eventPublisher;
}
protected void unsetEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setManagedItemProvider(ManagedItemProvider managedItemProvider) {
this.managedItemProvider = managedItemProvider;
}
protected void unsetManagedItemProvider(ManagedItemProvider managedItemProvider) {
this.managedItemProvider = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setDTOMapper(DTOMapper dtoMapper) {
this.dtoMapper = dtoMapper;
}
protected void unsetDTOMapper(DTOMapper dtoMapper) {
this.dtoMapper = dtoMapper;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setMetadataSelectorMatcher(MetadataSelectorMatcher metadataSelectorMatcher) {
this.metadataSelectorMatcher = metadataSelectorMatcher;
}
protected void unsetMetadataSelectorMatcher(MetadataSelectorMatcher metadataSelectorMatcher) {
this.metadataSelectorMatcher = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
public void setItemBuilderFactory(ItemBuilderFactory itemBuilderFactory) {
this.itemBuilderFactory = itemBuilderFactory;
}
public void unsetItemBuilderFactory(ItemBuilderFactory itemBuilderFactory) {
this.itemBuilderFactory = null;
this.itemRegistry = itemRegistry;
this.localeService = localeService;
this.managedItemProvider = managedItemProvider;
this.metadataRegistry = metadataRegistry;
this.metadataSelectorMatcher = metadataSelectorMatcher;
}
private UriBuilder uriBuilder(final UriInfo uriInfo, final HttpHeaders httpHeaders) {
@ -249,11 +196,11 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 200, message = "OK", response = EnrichedItemDTO.class, responseContainer = "List") })
public Response getItems(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("type") @ApiParam(value = "item type filter", required = false) @Nullable String type,
@QueryParam("tags") @ApiParam(value = "item tag filter", required = false) @Nullable String tags,
@QueryParam("metadata") @ApiParam(value = "metadata selector", required = false) @Nullable String namespaceSelector,
@DefaultValue("false") @QueryParam("recursive") @ApiParam(value = "get member items recursively", required = false) boolean recursive,
@QueryParam("fields") @ApiParam(value = "limit output to the given fields (comma separated)", required = false) @Nullable String fields) {
@QueryParam("type") @ApiParam(value = "item type filter") @Nullable String type,
@QueryParam("tags") @ApiParam(value = "item tag filter") @Nullable String tags,
@QueryParam("metadata") @ApiParam(value = "metadata selector") @Nullable String namespaceSelector,
@DefaultValue("false") @QueryParam("recursive") @ApiParam(value = "get member items recursively") boolean recursive,
@QueryParam("fields") @ApiParam(value = "limit output to the given fields (comma separated)") @Nullable String fields) {
final Locale locale = localeService.getLocale(language);
final Set<String> namespaces = splitAndFilterNamespaces(namespaceSelector, locale);
@ -276,8 +223,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 404, message = "Item not found") })
public Response getItemData(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("metadata") @ApiParam(value = "metadata selector", required = false) @Nullable String namespaceSelector,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname) {
@QueryParam("metadata") @ApiParam(value = "metadata selector") @Nullable String namespaceSelector,
@PathParam("itemname") @ApiParam(value = "item name") String itemname) {
final Locale locale = localeService.getLocale(language);
final Set<String> namespaces = splitAndFilterNamespaces(namespaceSelector, locale);
@ -311,8 +258,7 @@ public class ItemResource implements RESTResource {
@ApiOperation(value = "Gets the state of an item.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Item not found") })
public Response getPlainItemState(
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname) {
public Response getPlainItemState(@PathParam("itemname") @ApiParam(value = "item name") String itemname) {
// get item
Item item = getItem(itemname);
@ -335,8 +281,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 404, message = "Item not found"),
@ApiResponse(code = 400, message = "Item state null") })
public Response putItemState(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@ApiParam(value = "valid item state (e.g. ON, OFF)", required = true) String value) {
final Locale locale = localeService.getLocale(language);
@ -370,8 +316,7 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found"),
@ApiResponse(code = 400, message = "Item command null") })
public Response postItemCommand(
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
public Response postItemCommand(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@ApiParam(value = "valid item command (e.g. ON, OFF, UP, DOWN, REFRESH)", required = true) String value) {
Item item = getItem(itemname);
Command command = null;
@ -412,8 +357,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item or member item not found or item is not of type group item."),
@ApiResponse(code = 405, message = "Member item is not editable.") })
public Response addMember(@PathParam("itemName") @ApiParam(value = "item name", required = true) String itemName,
@PathParam("memberItemName") @ApiParam(value = "member item name", required = true) String memberItemName) {
public Response addMember(@PathParam("itemName") @ApiParam(value = "item name") String itemName,
@PathParam("memberItemName") @ApiParam(value = "member item name") String memberItemName) {
try {
Item item = itemRegistry.getItem(itemName);
@ -450,8 +395,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item or member item not found or item is not of type group item."),
@ApiResponse(code = 405, message = "Member item is not editable.") })
public Response removeMember(@PathParam("itemName") @ApiParam(value = "item name", required = true) String itemName,
@PathParam("memberItemName") @ApiParam(value = "member item name", required = true) String memberItemName) {
public Response removeMember(@PathParam("itemName") @ApiParam(value = "item name") String itemName,
@PathParam("memberItemName") @ApiParam(value = "member item name") String memberItemName) {
try {
Item item = itemRegistry.getItem(itemName);
@ -487,7 +432,7 @@ public class ItemResource implements RESTResource {
@ApiOperation(value = "Removes an item from the registry.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found or item is not editable.") })
public Response removeItem(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname) {
public Response removeItem(@PathParam("itemname") @ApiParam(value = "item name") String itemname) {
if (managedItemProvider.remove(itemname) == null) {
return Response.status(Status.NOT_FOUND).build();
}
@ -501,8 +446,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Item not editable.") })
public Response addTag(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@PathParam("tag") @ApiParam(value = "tag", required = true) String tag) {
public Response addTag(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("tag") @ApiParam(value = "tag") String tag) {
Item item = getItem(itemname);
if (item == null) {
@ -526,8 +471,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Item not editable.") })
public Response removeTag(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@PathParam("tag") @ApiParam(value = "tag", required = true) String tag) {
public Response removeTag(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("tag") @ApiParam(value = "tag") String tag) {
Item item = getItem(itemname);
if (item == null) {
@ -555,8 +500,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 400, message = "Metadata value empty."), //
@ApiResponse(code = 404, message = "Item not found."), //
@ApiResponse(code = 405, message = "Metadata not editable.") })
public Response addMetadata(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@PathParam("namespace") @ApiParam(value = "namespace", required = true) String namespace,
public Response addMetadata(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("namespace") @ApiParam(value = "namespace") String namespace,
@ApiParam(value = "metadata", required = true) MetadataDTO metadata) {
Item item = getItem(itemname);
@ -587,9 +532,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Meta data not editable.") })
public Response removeMetadata(
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@PathParam("namespace") @ApiParam(value = "namespace", required = true) String namespace) {
public Response removeMetadata(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("namespace") @ApiParam(value = "namespace") String namespace) {
Item item = getItem(itemname);
if (item == null) {
@ -625,8 +569,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Item not editable.") })
public Response createOrUpdateItem(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@ApiParam(value = "item data", required = true) @Nullable GroupItemDTO item) {
final Locale locale = localeService.getLocale(language);
@ -826,11 +770,4 @@ public class ItemResource implements RESTResource {
private boolean isEditable(String itemName) {
return managedItemProvider.get(itemName) != null;
}
@Override
public boolean isSatisfied() {
return itemRegistry != null && managedItemProvider != null && eventPublisher != null
&& itemBuilderFactory != null && dtoMapper != null && metadataRegistry != null
&& metadataSelectorMatcher != null && localeService != null;
}
}

View File

@ -24,12 +24,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
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;
import org.openhab.core.auth.Role;
import org.openhab.core.config.core.Configuration;
@ -42,10 +41,9 @@ import org.openhab.core.thing.link.AbstractLink;
import org.openhab.core.thing.link.ItemChannelLink;
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.openhab.core.thing.link.dto.ItemChannelLinkDTO;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -76,15 +74,18 @@ import io.swagger.annotations.ApiResponses;
@Path(ItemChannelLinkResource.PATH_LINKS)
@RolesAllowed({ Role.ADMIN })
@Api(ItemChannelLinkResource.PATH_LINKS)
@NonNullByDefault
public class ItemChannelLinkResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_LINKS = "links";
private ItemChannelLinkRegistry itemChannelLinkRegistry;
private final ItemChannelLinkRegistry itemChannelLinkRegistry;
@Context
UriInfo uriInfo;
@Activate
public ItemChannelLinkResource(final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@ -92,8 +93,8 @@ public class ItemChannelLinkResource implements RESTResource {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ItemChannelLinkDTO.class, responseContainer = "Collection") })
public Response getAll(
@QueryParam("channelUID") @ApiParam(value = "filter by channel UID", required = false) @Nullable String channelUID,
@QueryParam("itemName") @ApiParam(value = "filter by item name", required = false) @Nullable String itemName) {
@QueryParam("channelUID") @ApiParam(value = "filter by channel UID") @Nullable String channelUID,
@QueryParam("itemName") @ApiParam(value = "filter by item name") @Nullable String itemName) {
Stream<ItemChannelLinkDTO> linkStream = itemChannelLinkRegistry.getAll().stream().map(this::toBeans);
if (channelUID != null) {
@ -134,7 +135,7 @@ public class ItemChannelLinkResource implements RESTResource {
@ApiResponse(code = 405, message = "Link is not editable") })
public Response link(@PathParam("itemName") @ApiParam(value = "itemName") String itemName,
@PathParam("channelUID") @ApiParam(value = "channelUID") String channelUid,
@ApiParam(value = "link data", required = false) ItemChannelLinkDTO bean) {
@ApiParam(value = "link data") @Nullable ItemChannelLinkDTO bean) {
ItemChannelLink link;
if (bean == null) {
link = new ItemChannelLink(itemName, new ChannelUID(channelUid), new Configuration());
@ -182,22 +183,8 @@ public class ItemChannelLinkResource implements RESTResource {
}
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setItemChannelLinkRegistry(ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
}
protected void unsetItemChannelLinkRegistry(ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = null;
}
private ItemChannelLinkDTO toBeans(ItemChannelLink link) {
return new ItemChannelLinkDTO(link.getItemName(), link.getLinkedUID().toString(),
link.getConfiguration().getProperties());
}
@Override
public boolean isSatisfied() {
return itemChannelLinkRegistry != null;
}
}

View File

@ -35,6 +35,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.rest.JSONResponse;
@ -58,10 +60,9 @@ import org.openhab.core.persistence.dto.ItemHistoryDTO;
import org.openhab.core.persistence.dto.PersistenceServiceDTO;
import org.openhab.core.types.State;
import org.openhab.core.types.TypeParser;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -94,57 +95,33 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired
@Path(PersistenceResource.PATH_PERSISTENCE)
@Api(PersistenceResource.PATH_PERSISTENCE)
@NonNullByDefault
public class PersistenceResource implements RESTResource {
// The URI path to this resource
public static final String PATH_PERSISTENCE = "persistence";
private final Logger logger = LoggerFactory.getLogger(PersistenceResource.class);
private static final String MODIFYABLE = "Modifiable";
private static final String QUERYABLE = "Queryable";
private static final String STANDARD = "Standard";
// The URI path to this resource
public static final String PATH_PERSISTENCE = "persistence";
private final ItemRegistry itemRegistry;
private final LocaleService localeService;
private final PersistenceServiceRegistry persistenceServiceRegistry;
private final TimeZoneProvider timeZoneProvider;
private ItemRegistry itemRegistry;
private PersistenceServiceRegistry persistenceServiceRegistry;
private TimeZoneProvider timeZoneProvider;
private LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setPersistenceServiceRegistry(PersistenceServiceRegistry persistenceServiceRegistry) {
this.persistenceServiceRegistry = persistenceServiceRegistry;
}
protected void unsetPersistenceServiceRegistry(PersistenceServiceRegistry persistenceServiceRegistry) {
this.persistenceServiceRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setTimeZoneProvider(TimeZoneProvider timeZoneProvider) {
this.timeZoneProvider = timeZoneProvider;
}
protected void unsetTimeZoneProvider(TimeZoneProvider timeZoneProvider) {
this.timeZoneProvider = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setItemRegistry(ItemRegistry itemRegistry) {
@Activate
public PersistenceResource( //
final @Reference ItemRegistry itemRegistry, //
final @Reference LocaleService localeService,
final @Reference PersistenceServiceRegistry persistenceServiceRegistry,
final @Reference TimeZoneProvider timeZoneProvider) {
this.itemRegistry = itemRegistry;
}
protected void unsetItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.persistenceServiceRegistry = persistenceServiceRegistry;
this.timeZoneProvider = timeZoneProvider;
}
@GET
@ -153,7 +130,7 @@ public class PersistenceResource implements RESTResource {
@ApiOperation(value = "Gets a list of persistence services.", response = String.class, responseContainer = "List")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = String.class, responseContainer = "List"))
public Response httpGetPersistenceServices(@Context HttpHeaders headers,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
Locale locale = localeService.getLocale(language);
Object responseObject = getPersistenceServiceList(locale);
@ -167,7 +144,7 @@ public class PersistenceResource implements RESTResource {
@ApiOperation(value = "Gets a list of items available via a specific persistence service.", response = String.class, responseContainer = "List")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = String.class, responseContainer = "List"))
public Response httpGetPersistenceServiceItems(@Context HttpHeaders headers,
@ApiParam(value = "Id of the persistence service. If not provided the default service will be used", required = false) @QueryParam("serviceId") String serviceId) {
@ApiParam(value = "Id of the persistence service. If not provided the default service will be used") @QueryParam("serviceId") @Nullable String serviceId) {
return getServiceItemList(serviceId);
}
@ -179,17 +156,16 @@ public class PersistenceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ItemHistoryDTO.class),
@ApiResponse(code = 404, message = "Unknown Item or persistence service") })
public Response httpGetPersistenceItemData(@Context HttpHeaders headers,
@ApiParam(value = "Id of the persistence service. If not provided the default service will be used", required = false) @QueryParam("serviceId") String serviceId,
@ApiParam(value = "The item name", required = true) @PathParam("itemname") String itemName,
@ApiParam(value = "Id of the persistence service. If not provided the default service will be used") @QueryParam("serviceId") @Nullable String serviceId,
@ApiParam(value = "The item name") @PathParam("itemname") String itemName,
@ApiParam(value = "Start time of the data to return. Will default to 1 day before endtime. ["
+ DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS
+ "]", required = false) @QueryParam("starttime") String startTime,
+ "]") @QueryParam("starttime") @Nullable String startTime,
@ApiParam(value = "End time of the data to return. Will default to current time. ["
+ DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS
+ "]", required = false) @QueryParam("endtime") String endTime,
@ApiParam(value = "Page number of data to return. This parameter will enable paging.", required = false) @QueryParam("page") int pageNumber,
@ApiParam(value = "The length of each page.", required = false) @QueryParam("pagelength") int pageLength,
@ApiParam(value = "Gets one value before and after the requested period.", required = false) @QueryParam("boundary") boolean boundary) {
+ DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS + "]") @QueryParam("endtime") @Nullable String endTime,
@ApiParam(value = "Page number of data to return. This parameter will enable paging.") @QueryParam("page") int pageNumber,
@ApiParam(value = "The length of each page.") @QueryParam("pagelength") int pageLength,
@ApiParam(value = "Gets one value before and after the requested period.") @QueryParam("boundary") boolean boundary) {
return getItemHistoryDTO(serviceId, itemName, startTime, endTime, pageNumber, pageLength, boundary);
}
@ -204,7 +180,7 @@ public class PersistenceResource implements RESTResource {
@ApiResponse(code = 404, message = "Unknown persistence service") })
public Response httpDeletePersistenceServiceItem(@Context HttpHeaders headers,
@ApiParam(value = "Id of the persistence service.", required = true) @QueryParam("serviceId") String serviceId,
@ApiParam(value = "The item name.", required = true) @PathParam("itemname") String itemName,
@ApiParam(value = "The item name.") @PathParam("itemname") String itemName,
@ApiParam(value = "Start time of the data to return. [" + DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS
+ "]", required = true) @QueryParam("starttime") String startTime,
@ApiParam(value = "End time of the data to return. [" + DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS
@ -220,8 +196,8 @@ public class PersistenceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ItemHistoryDTO.class),
@ApiResponse(code = 404, message = "Unknown Item or persistence service") })
public Response httpPutPersistenceItemData(@Context HttpHeaders headers,
@ApiParam(value = "Id of the persistence service. If not provided the default service will be used", required = false) @QueryParam("serviceId") String serviceId,
@ApiParam(value = "The item name.", required = true) @PathParam("itemname") String itemName,
@ApiParam(value = "Id of the persistence service. If not provided the default service will be used") @QueryParam("serviceId") @Nullable String serviceId,
@ApiParam(value = "The item name.") @PathParam("itemname") String itemName,
@ApiParam(value = "Time of the data to be stored. Will default to current time. ["
+ DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS + "]", required = true) @QueryParam("time") String time,
@ApiParam(value = "The state to store.", required = true) @QueryParam("state") String value) {
@ -233,22 +209,26 @@ public class PersistenceResource implements RESTResource {
return dateTime.getZonedDateTime();
}
private Response getItemHistoryDTO(String serviceId, String itemName, String timeBegin, String timeEnd,
int pageNumber, int pageLength, boolean boundary) {
private Response getItemHistoryDTO(@Nullable String serviceId, String itemName, @Nullable String timeBegin,
@Nullable String timeEnd, int pageNumber, int pageLength, boolean boundary) {
// Benchmarking timer...
long timerStart = System.currentTimeMillis();
@Nullable
ItemHistoryDTO dto = createDTO(serviceId, itemName, timeBegin, timeEnd, pageNumber, pageLength, boundary);
if (dto == null) {
JSONResponse.createErrorResponse(Status.BAD_REQUEST, "Persistence service not queryable: " + serviceId);
return JSONResponse.createErrorResponse(Status.BAD_REQUEST,
"Persistence service not queryable: " + serviceId);
}
logger.debug("Persistence returned {} rows in {}ms", dto.datapoints, System.currentTimeMillis() - timerStart);
return JSONResponse.createResponse(Status.OK, dto, "");
}
protected ItemHistoryDTO createDTO(String serviceId, String itemName, String timeBegin, String timeEnd,
int pageNumber, int pageLength, boolean boundary) {
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;
String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId();
@ -315,7 +295,7 @@ public class PersistenceResource implements RESTResource {
filter.setPageSize(1);
filter.setOrdering(Ordering.DESCENDING);
result = qService.query(filter);
if (result != null && result.iterator().hasNext()) {
if (result.iterator().hasNext()) {
dto.addData(dateTimeBegin.toInstant().toEpochMilli(), result.iterator().next().getState());
quantity++;
}
@ -334,28 +314,26 @@ public class PersistenceResource implements RESTResource {
filter.setOrdering(Ordering.ASCENDING);
result = qService.query(filter);
if (result != null) {
Iterator<HistoricItem> it = result.iterator();
Iterator<HistoricItem> it = result.iterator();
// Iterate through the data
HistoricItem lastItem = null;
while (it.hasNext()) {
HistoricItem historicItem = it.next();
state = historicItem.getState();
// Iterate through the data
HistoricItem lastItem = null;
while (it.hasNext()) {
HistoricItem historicItem = it.next();
state = historicItem.getState();
// For 'binary' states, we need to replicate the data
// to avoid diagonal lines
if (state instanceof OnOffType || state instanceof OpenClosedType) {
if (lastItem != null) {
dto.addData(historicItem.getTimestamp().getTime(), lastItem.getState());
quantity++;
}
// For 'binary' states, we need to replicate the data
// to avoid diagonal lines
if (state instanceof OnOffType || state instanceof OpenClosedType) {
if (lastItem != null) {
dto.addData(historicItem.getTimestamp().getTime(), lastItem.getState());
quantity++;
}
dto.addData(historicItem.getTimestamp().getTime(), state);
quantity++;
lastItem = historicItem;
}
dto.addData(historicItem.getTimestamp().getTime(), state);
quantity++;
lastItem = historicItem;
}
if (boundary) {
@ -364,7 +342,7 @@ public class PersistenceResource implements RESTResource {
filter.setPageSize(1);
filter.setOrdering(Ordering.ASCENDING);
result = qService.query(filter);
if (result != null && result.iterator().hasNext()) {
if (result.iterator().hasNext()) {
dto.addData(dateTimeEnd.toInstant().toEpochMilli(), result.iterator().next().getState());
quantity++;
}
@ -401,7 +379,7 @@ public class PersistenceResource implements RESTResource {
return dtoList;
}
private Response getServiceItemList(String serviceId) {
private Response getServiceItemList(@Nullable String serviceId) {
// If serviceId is null, then use the default service
PersistenceService service = null;
if (serviceId == null) {
@ -426,7 +404,8 @@ public class PersistenceResource implements RESTResource {
return JSONResponse.createResponse(Status.OK, qService.getItemInfo(), "");
}
private Response deletePersistenceItemData(String serviceId, String itemName, String timeBegin, String timeEnd) {
private Response deletePersistenceItemData(@Nullable String serviceId, String itemName, @Nullable String timeBegin,
@Nullable String timeEnd) {
// For deleting, we must specify a service id - don't use the default service
if (serviceId == null || serviceId.length() == 0) {
logger.debug("Persistence service must be specified for delete operations.");
@ -448,7 +427,7 @@ public class PersistenceResource implements RESTResource {
ModifiablePersistenceService mService = (ModifiablePersistenceService) service;
if (timeBegin == null | timeEnd == null) {
if (timeBegin == null || timeEnd == null) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, "The start and end time must be set");
}
@ -476,11 +455,10 @@ public class PersistenceResource implements RESTResource {
return Response.status(Status.OK).build();
}
private Response putItemState(String serviceId, String itemName, String value, String time) {
private Response putItemState(@Nullable String serviceId, String itemName, String value, @Nullable String time) {
// If serviceId is null, then use the default service
PersistenceService service = null;
String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId();
service = persistenceServiceRegistry.get(effectiveServiceId);
PersistenceService service = persistenceServiceRegistry.get(effectiveServiceId);
if (service == null) {
logger.warn("Persistence service not found '{}'.", effectiveServiceId);
@ -490,10 +468,6 @@ public class PersistenceResource implements RESTResource {
Item item;
try {
if (itemRegistry == null) {
logger.warn("Item registry not set.");
return JSONResponse.createErrorResponse(Status.CONFLICT, "Item registry not set.");
}
item = itemRegistry.getItem(itemName);
} catch (ItemNotFoundException e) {
logger.warn("Item not found '{}'.", itemName);
@ -528,10 +502,4 @@ public class PersistenceResource implements RESTResource {
mService.store(item, Date.from(dateTime.toInstant()), state);
return Response.status(Status.OK).build();
}
@Override
public boolean isSatisfied() {
return itemRegistry != null && persistenceServiceRegistry != null && timeZoneProvider != null
&& localeService != null;
}
}

View File

@ -27,6 +27,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.io.rest.LocaleService;
@ -43,17 +44,14 @@ import org.openhab.core.thing.profiles.dto.ProfileTypeDTOMapper;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -75,16 +73,25 @@ import io.swagger.annotations.ApiResponses;
@Path(ProfileTypeResource.PATH_PROFILE_TYPES)
@RolesAllowed({ Role.ADMIN })
@Api(ProfileTypeResource.PATH_PROFILE_TYPES)
@NonNullByDefault
public class ProfileTypeResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_PROFILE_TYPES = "profile-types";
private final Logger logger = LoggerFactory.getLogger(ProfileTypeResource.class);
private final ChannelTypeRegistry channelTypeRegistry;
private final LocaleService localeService;
private final ProfileTypeRegistry profileTypeRegistry;
private ProfileTypeRegistry profileTypeRegistry;
private ChannelTypeRegistry channelTypeRegistry;
private LocaleService localeService;
@Activate
public ProfileTypeResource( //
final @Reference ChannelTypeRegistry channelTypeRegistry, //
final @Reference LocaleService localeService, //
final @Reference ProfileTypeRegistry profileTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
this.localeService = localeService;
this.profileTypeRegistry = profileTypeRegistry;
}
@GET
@RolesAllowed({ Role.USER })
@ -92,19 +99,20 @@ public class ProfileTypeResource implements RESTResource {
@ApiOperation(value = "Gets all available profile types.", response = ProfileTypeDTO.class, responseContainer = "Set")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ProfileTypeDTO.class, responseContainer = "Set"))
public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language,
@QueryParam("channelTypeUID") @ApiParam(value = "channel type filter", required = false) @Nullable String channelTypeUID,
@QueryParam("itemType") @ApiParam(value = "item type filter", required = false) @Nullable String itemType) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("channelTypeUID") @ApiParam(value = "channel type filter") @Nullable String channelTypeUID,
@QueryParam("itemType") @ApiParam(value = "item type filter") @Nullable String itemType) {
Locale locale = localeService.getLocale(language);
return Response.ok(new Stream2JSONInputStream(getProfileTypes(locale, channelTypeUID, itemType))).build();
}
protected Stream<ProfileTypeDTO> getProfileTypes(Locale locale, String channelTypeUID, String itemType) {
protected Stream<ProfileTypeDTO> getProfileTypes(@Nullable Locale locale, @Nullable String channelTypeUID,
@Nullable String itemType) {
return profileTypeRegistry.getProfileTypes(locale).stream().filter(matchesChannelUID(channelTypeUID, locale))
.filter(matchesItemType(itemType)).map(t -> convertToProfileTypeDTO(t, locale));
.filter(matchesItemType(itemType)).map(profileType -> ProfileTypeDTOMapper.map(profileType));
}
private Predicate<ProfileType> matchesChannelUID(String channelTypeUID, Locale locale) {
private Predicate<ProfileType> matchesChannelUID(@Nullable String channelTypeUID, @Nullable Locale locale) {
if (channelTypeUID == null) {
return t -> true;
}
@ -122,7 +130,7 @@ public class ProfileTypeResource implements RESTResource {
return t -> false;
}
private Predicate<ProfileType> matchesItemType(String itemType) {
private Predicate<ProfileType> matchesItemType(@Nullable String itemType) {
if (itemType == null) {
return t -> true;
}
@ -171,47 +179,4 @@ public class ProfileTypeResource implements RESTResource {
}
return false;
}
private ProfileTypeDTO convertToProfileTypeDTO(ProfileType profileType, Locale locale) {
final ProfileTypeDTO profileTypeDTO = ProfileTypeDTOMapper.map(profileType);
if (profileTypeDTO != null) {
return profileTypeDTO;
} else {
logger.warn("Cannot create DTO for profileType '{}'. Skipping it.", profileTypeDTO);
}
return null;
}
@Override
public boolean isSatisfied() {
return (this.profileTypeRegistry != null && channelTypeRegistry != null);
}
@Reference
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setProfileTypeRegistry(ProfileTypeRegistry registry) {
this.profileTypeRegistry = registry;
}
protected void unsetProfileTypeRegistry(ProfileTypeRegistry registry) {
this.profileTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setChannelTypeRegistry(ChannelTypeRegistry registry) {
this.channelTypeRegistry = registry;
}
protected void unsetChannelTypeRegistry(ChannelTypeRegistry registry) {
this.channelTypeRegistry = null;
}
}

View File

@ -35,6 +35,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigConstants;
import org.openhab.core.config.core.ConfigDescription;
@ -55,8 +57,6 @@ import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -87,6 +87,7 @@ import io.swagger.annotations.ApiResponses;
@Path(ConfigurableServiceResource.PATH_SERVICES)
@RolesAllowed({ Role.ADMIN })
@Api(ConfigurableServiceResource.PATH_SERVICES)
@NonNullByDefault
public class ConfigurableServiceResource implements RESTResource {
/** The URI path to this resource */
@ -104,13 +105,17 @@ public class ConfigurableServiceResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(ConfigurableServiceResource.class);
private final BundleContext bundleContext;
private ConfigurationService configurationService;
private ConfigDescriptionRegistry configDescRegistry;
private final ConfigDescriptionRegistry configDescRegistry;
private final ConfigurationService configurationService;
@Activate
public ConfigurableServiceResource(final BundleContext bundleContext) {
public ConfigurableServiceResource( //
final BundleContext bundleContext, //
final @Reference ConfigurationService configurationService,
final @Reference ConfigDescriptionRegistry configDescRegistry) {
this.bundleContext = bundleContext;
this.configDescRegistry = configDescRegistry;
this.configurationService = configurationService;
}
@GET
@ -129,7 +134,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiOperation(value = "Get configurable service for given service ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ConfigurableServiceDTO.class),
@ApiResponse(code = 404, message = "Not found") })
public Response getById(@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId) {
public Response getById(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId) {
ConfigurableServiceDTO configurableService = getServiceById(serviceId);
if (configurableService != null) {
return Response.ok(configurableService).build();
@ -138,7 +143,7 @@ public class ConfigurableServiceResource implements RESTResource {
}
}
private ConfigurableServiceDTO getServiceById(String serviceId) {
private @Nullable ConfigurableServiceDTO getServiceById(String serviceId) {
ConfigurableServiceDTO multiService = getMultiConfigServiceById(serviceId);
if (multiService != null) {
return multiService;
@ -153,7 +158,7 @@ public class ConfigurableServiceResource implements RESTResource {
return null;
}
private ConfigurableServiceDTO getMultiConfigServiceById(String serviceId) {
private @Nullable ConfigurableServiceDTO getMultiConfigServiceById(String serviceId) {
String filter = "(&(" + Constants.SERVICE_PID + "=" + serviceId + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID
+ "=*))";
List<ConfigurableServiceDTO> services = getServicesByFilter(filter);
@ -170,7 +175,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ConfigurableServiceDTO.class, responseContainer = "List") })
public List<ConfigurableServiceDTO> getMultiConfigServicesByFactoryPid(
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId) {
@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId) {
List<ConfigurableServiceDTO> services = collectServicesById(serviceId);
return services;
}
@ -186,8 +191,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiOperation(value = "Get service configuration for given service ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 500, message = "Configuration can not be read due to internal error") })
public Response getConfiguration(
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId) {
public Response getConfiguration(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId) {
try {
Configuration configuration = configurationService.get(serviceId);
return configuration != null ? Response.ok(configuration.getProperties()).build()
@ -206,9 +210,8 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 204, message = "No old configuration"),
@ApiResponse(code = 500, message = "Configuration can not be updated due to internal error") })
public Response updateConfiguration(
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId,
Map<String, Object> configuration) {
public Response updateConfiguration(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId,
@Nullable Map<String, Object> configuration) {
try {
Configuration oldConfiguration = configurationService.get(serviceId);
configurationService.update(serviceId, new Configuration(normalizeConfiguration(configuration, serviceId)));
@ -220,7 +223,8 @@ public class ConfigurableServiceResource implements RESTResource {
}
}
private Map<String, Object> normalizeConfiguration(Map<String, Object> properties, String serviceId) {
private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
String serviceId) {
if (properties == null || properties.isEmpty()) {
return properties;
}
@ -253,8 +257,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 204, message = "No old configuration"),
@ApiResponse(code = 500, message = "Configuration can not be deleted due to internal error") })
public Response deleteConfiguration(
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId) {
public Response deleteConfiguration(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId) {
try {
Configuration oldConfiguration = configurationService.get(serviceId);
configurationService.delete(serviceId);
@ -300,7 +303,7 @@ public class ConfigurableServiceResource implements RESTResource {
return services;
}
private String getConfigDescriptionByFactoryPid(String factoryPid) {
private @Nullable String getConfigDescriptionByFactoryPid(String factoryPid) {
String configDescriptionURI = null;
String filter = "(" + Constants.SERVICE_PID + "=" + factoryPid + ")";
@ -379,27 +382,4 @@ public class ConfigurableServiceResource implements RESTResource {
return first;
}
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
protected void unsetConfigurationService(ConfigurationService configurationService) {
this.configurationService = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescRegistry = null;
}
@Override
public boolean isSatisfied() {
return configurationService != null && configDescRegistry != null;
}
}

View File

@ -46,6 +46,8 @@ 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;
import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigDescription;
import org.openhab.core.config.core.ConfigDescriptionRegistry;
@ -94,10 +96,9 @@ import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.thing.type.ThingType;
import org.openhab.core.thing.type.ThingTypeRegistry;
import org.openhab.core.thing.util.ThingHelper;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -136,6 +137,7 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired
@Path(ThingResource.PATH_THINGS)
@Api(ThingResource.PATH_THINGS)
@NonNullByDefault
public class ThingResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(ThingResource.class);
@ -143,34 +145,59 @@ public class ThingResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_THINGS = "things";
private ItemChannelLinkRegistry itemChannelLinkRegistry;
private ItemFactory itemFactory;
private ItemRegistry itemRegistry;
private ManagedItemChannelLinkProvider managedItemChannelLinkProvider;
private ManagedItemProvider managedItemProvider;
private ManagedThingProvider managedThingProvider;
private ThingRegistry thingRegistry;
private ConfigStatusService configStatusService;
private ConfigDescriptionRegistry configDescRegistry;
private ThingTypeRegistry thingTypeRegistry;
private ChannelTypeRegistry channelTypeRegistry;
private ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService;
private FirmwareUpdateService firmwareUpdateService;
private FirmwareRegistry firmwareRegistry;
private ThingManager thingManager;
private final ChannelTypeRegistry channelTypeRegistry;
private final ConfigStatusService configStatusService;
private final ConfigDescriptionRegistry configDescRegistry;
private final FirmwareRegistry firmwareRegistry;
private final FirmwareUpdateService firmwareUpdateService;
private final ItemChannelLinkRegistry itemChannelLinkRegistry;
private final ItemFactory itemFactory;
private final ItemRegistry itemRegistry;
private final LocaleService localeService;
private final ManagedItemChannelLinkProvider managedItemChannelLinkProvider;
private final ManagedItemProvider managedItemProvider;
private final ManagedThingProvider managedThingProvider;
private final ThingManager thingManager;
private final ThingRegistry thingRegistry;
private final ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService;
private final ThingTypeRegistry thingTypeRegistry;
private LocaleService localeService;
private @Context @NonNullByDefault({}) UriInfo uriInfo;
@Context
private UriInfo uriInfo;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
@Activate
public ThingResource( //
final @Reference ChannelTypeRegistry channelTypeRegistry,
final @Reference ConfigStatusService configStatusService,
final @Reference ConfigDescriptionRegistry configDescRegistry,
final @Reference FirmwareRegistry firmwareRegistry,
final @Reference FirmwareUpdateService firmwareUpdateService,
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, //
final @Reference ItemFactory itemFactory, //
final @Reference ItemRegistry itemRegistry, //
final @Reference LocaleService localeService,
final @Reference ManagedItemChannelLinkProvider managedItemChannelLinkProvider,
final @Reference ManagedItemProvider managedItemProvider,
final @Reference ManagedThingProvider managedThingProvider, //
final @Reference ThingManager thingManager, //
final @Reference ThingRegistry thingRegistry,
final @Reference ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService,
final @Reference ThingTypeRegistry thingTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
this.configStatusService = configStatusService;
this.configDescRegistry = configDescRegistry;
this.firmwareRegistry = firmwareRegistry;
this.firmwareUpdateService = firmwareUpdateService;
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.itemFactory = itemFactory;
this.itemRegistry = itemRegistry;
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.managedItemChannelLinkProvider = managedItemChannelLinkProvider;
this.managedItemProvider = managedItemProvider;
this.managedThingProvider = managedThingProvider;
this.thingManager = thingManager;
this.thingRegistry = thingRegistry;
this.thingStatusInfoI18nLocalizationService = thingStatusInfoI18nLocalizationService;
this.thingTypeRegistry = thingTypeRegistry;
}
/**
@ -186,7 +213,8 @@ public class ThingResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 201, message = "Created", response = String.class),
@ApiResponse(code = 400, message = "A uid must be provided, if no binding can create a thing of this type."),
@ApiResponse(code = 409, message = "A thing with the same uid already exists.") })
public Response create(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
public Response create(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@ApiParam(value = "thing data", required = true) ThingDTO thingBean) {
final Locale locale = localeService.getLocale(language);
@ -212,7 +240,9 @@ public class ThingResource implements RESTResource {
// turn the ThingDTO's configuration into a Configuration
Configuration configuration = new Configuration(
normalizeConfiguration(thingBean.configuration, thingTypeUID, thingUID));
normalizeChannels(thingBean, thingUID);
if (thingUID != null) {
normalizeChannels(thingBean, thingUID);
}
Thing thing = thingRegistry.createThingOfType(thingTypeUID, thingUID, bridgeUID, thingBean.label,
configuration);
@ -254,7 +284,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Get all available things.", response = EnrichedThingDTO.class, responseContainer = "Set")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = EnrichedThingDTO.class, responseContainer = "Set") })
public Response getAll(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language) {
public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
final Locale locale = localeService.getLocale(language);
Stream<EnrichedThingDTO> thingStream = thingRegistry.stream().map(t -> convertToEnrichedThingDTO(t, locale))
@ -269,7 +300,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing by UID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ThingDTO.class),
@ApiResponse(code = 404, message = "Thing not found.") })
public Response getByUID(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
public Response getByUID(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID) {
final Locale locale = localeService.getLocale(language);
@ -300,7 +332,8 @@ public class ThingResource implements RESTResource {
@ApiResponse(code = 202, message = "ACCEPTED for asynchronous deletion."),
@ApiResponse(code = 404, message = "Thing not found."),
@ApiResponse(code = 409, message = "Thing could not be deleted because it's not editable.") })
public Response remove(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
public Response remove(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@DefaultValue("false") @QueryParam("force") @ApiParam(value = "force") boolean force) {
final Locale locale = localeService.getLocale(language);
@ -318,7 +351,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists as a managed thing, so it can get
// updated, 409 otherwise
Thing managed = managedThingProvider.get(thingUIDObject);
if (null == managed) {
if (managed == null) {
logger.info("Received HTTP DELETE request for update at '{}' for an unmanaged thing '{}'.",
uriInfo.getPath(), thingUID);
return getThingResponse(Status.CONFLICT, thing, locale,
@ -327,12 +360,12 @@ public class ThingResource implements RESTResource {
// only move on if Thing is known to be managed, so it can get updated
if (force) {
if (null == thingRegistry.forceRemove(thingUIDObject)) {
if (thingRegistry.forceRemove(thingUIDObject) == null) {
return getThingResponse(Status.INTERNAL_SERVER_ERROR, thing, locale,
"Cannot delete Thing " + thingUID + " for unknown reasons.");
}
} else {
if (null != thingRegistry.remove(thingUIDObject)) {
if (thingRegistry.remove(thingUIDObject) != null) {
return getThingResponse(Status.ACCEPTED, thing, locale, null);
}
}
@ -356,7 +389,8 @@ public class ThingResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ThingDTO.class),
@ApiResponse(code = 404, message = "Thing not found."),
@ApiResponse(code = 409, message = "Thing could not be updated as it is not editable.") })
public Response update(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
public Response update(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@ApiParam(value = "thing", required = true) ThingDTO thingBean) throws IOException {
final Locale locale = localeService.getLocale(language);
@ -365,7 +399,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists at all, 404 otherwise
Thing thing = thingRegistry.get(thingUIDObject);
if (null == thing) {
if (thing == null) {
logger.info("Received HTTP PUT request for update at '{}' for the unknown thing '{}'.", uriInfo.getPath(),
thingUID);
return getThingNotFoundResponse(thingUID);
@ -374,7 +408,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists as a managed thing, so it can get
// updated, 409 otherwise
Thing managed = managedThingProvider.get(thingUIDObject);
if (null == managed) {
if (managed == null) {
logger.info("Received HTTP PUT request for update at '{}' for an unmanaged thing '{}'.", uriInfo.getPath(),
thingUID);
return getThingResponse(Status.CONFLICT, thing, locale,
@ -390,7 +424,7 @@ public class ThingResource implements RESTResource {
// update, returns null in case Thing cannot be found
Thing oldthing = managedThingProvider.update(thing);
if (null == oldthing) {
if (oldthing == null) {
return getThingNotFoundResponse(thingUID);
}
@ -415,9 +449,10 @@ public class ThingResource implements RESTResource {
@ApiResponse(code = 400, message = "Configuration of the thing is not valid."),
@ApiResponse(code = 404, message = "Thing not found"),
@ApiResponse(code = 409, message = "Thing could not be updated as it is not editable.") })
public Response updateConfiguration(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) String language,
public Response updateConfiguration(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thing") String thingUID,
@ApiParam(value = "configuration parameters") Map<String, Object> configurationParameters)
@ApiParam(value = "configuration parameters") @Nullable Map<String, Object> configurationParameters)
throws IOException {
final Locale locale = localeService.getLocale(language);
@ -425,7 +460,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists at all, 404 otherwise
Thing thing = thingRegistry.get(thingUIDObject);
if (null == thing) {
if (thing == null) {
logger.info("Received HTTP PUT request for update configuration at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID);
@ -434,7 +469,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists as a managed thing, so it can get
// updated, 409 otherwise
Thing managed = managedThingProvider.get(thingUIDObject);
if (null == managed) {
if (managed == null) {
logger.info("Received HTTP PUT request for update configuration at '{}' for an unmanaged thing '{}'.",
uriInfo.getPath(), thingUID);
return getThingResponse(Status.CONFLICT, thing, locale,
@ -468,13 +503,14 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing's status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Thing not found.") })
public Response getStatus(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) String language,
public Response getStatus(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thing") String thingUID) throws IOException {
ThingUID thingUIDObject = new ThingUID(thingUID);
// Check if the Thing exists, 404 if not
Thing thing = thingRegistry.get(thingUIDObject);
if (null == thing) {
if (thing == null) {
logger.info("Received HTTP GET request for thing config status at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID);
@ -491,7 +527,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Sets the thing enabled status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Thing not found.") })
public Response setEnabled(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) String language,
public Response setEnabled(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thing") String thingUID,
@ApiParam(value = "enabled") String enabled) throws IOException {
final Locale locale = localeService.getLocale(language);
@ -500,7 +537,7 @@ public class ThingResource implements RESTResource {
// Check if the Thing exists, 404 if not
Thing thing = thingRegistry.get(thingUIDObject);
if (null == thing) {
if (thing == null) {
logger.info("Received HTTP PUT request for set enabled at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID);
@ -519,13 +556,14 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing's config status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Thing not found.") })
public Response getConfigStatus(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) String language,
public Response getConfigStatus(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@PathParam("thingUID") @ApiParam(value = "thing") String thingUID) throws IOException {
ThingUID thingUIDObject = new ThingUID(thingUID);
// Check if the Thing exists, 404 if not
Thing thing = thingRegistry.get(thingUIDObject);
if (null == thing) {
if (thing == null) {
logger.info("Received HTTP GET request for thing config status at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID);
@ -546,7 +584,7 @@ public class ThingResource implements RESTResource {
@ApiResponse(code = 400, message = "Firmware update preconditions not satisfied."),
@ApiResponse(code = 404, message = "Thing not found.") })
public Response updateFirmware(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thing") String thingUID,
@PathParam("firmwareVersion") @ApiParam(value = "version") String firmwareVersion) throws IOException {
Thing thing = thingRegistry.get(new ThingUID(thingUID));
@ -556,16 +594,15 @@ public class ThingResource implements RESTResource {
return getThingNotFoundResponse(thingUID);
}
if (firmwareVersion == null || firmwareVersion.isEmpty()) {
if (firmwareVersion.isEmpty()) {
logger.info(
"Received HTTP PUT request for firmware update at '{}' for thing '{}' with unknown firmware version '{}'.",
uriInfo.getPath(), thingUID, firmwareVersion);
return JSONResponse.createResponse(Status.BAD_REQUEST, null, "Firmware version is empty");
}
ThingUID uid = thing.getUID();
try {
firmwareUpdateService.updateFirmware(uid, firmwareVersion, localeService.getLocale(language));
firmwareUpdateService.updateFirmware(thing.getUID(), firmwareVersion, localeService.getLocale(language));
} catch (IllegalArgumentException | IllegalStateException ex) {
return JSONResponse.createResponse(Status.BAD_REQUEST, null,
"Firmware update preconditions not satisfied.");
@ -579,7 +616,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing's firmware status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 204, message = "No firmware status provided by this Thing.") })
public Response getFirmwareStatus(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) String language,
public Response getFirmwareStatus(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("thingUID") @ApiParam(value = "thing") String thingUID) throws IOException {
ThingUID thingUIDObject = new ThingUID(thingUID);
FirmwareStatusDTO firmwareStatusDto = getThingFirmwareStatusInfo(thingUIDObject);
@ -597,10 +635,10 @@ public class ThingResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 204, message = "No firmwares found.") })
public Response getFirmwares(@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
ThingUID aThingUID = new ThingUID(thingUID);
Thing thing = thingRegistry.get(aThingUID);
if (null == thing) {
if (thing == null) {
logger.info(
"Received HTTP GET request for listing available firmwares at {} for unknown thing with UID '{}'",
uriInfo.getPath(), thingUID);
@ -622,7 +660,7 @@ public class ThingResource implements RESTResource {
firmware.getPrerequisiteVersion(), firmware.getChangelog());
}
private FirmwareStatusDTO getThingFirmwareStatusInfo(ThingUID thingUID) {
private @Nullable FirmwareStatusDTO getThingFirmwareStatusInfo(ThingUID thingUID) {
FirmwareStatusInfo info = firmwareUpdateService.getFirmwareStatusInfo(thingUID);
if (info != null) {
return buildFirmwareStatusDTO(info);
@ -654,10 +692,11 @@ public class ThingResource implements RESTResource {
* @param errormessage an optional error message (may be null), ignored if the status family is successful
* @return Response
*/
private Response getThingResponse(Status status, Thing thing, Locale locale, String errormessage) {
private Response getThingResponse(Status status, @Nullable Thing thing, Locale locale,
@Nullable String errormessage) {
ThingStatusInfo thingStatusInfo = thingStatusInfoI18nLocalizationService.getLocalizedThingStatusInfo(thing,
locale);
boolean managed = managedThingProvider.get(thing.getUID()) != null;
boolean managed = thing != null && managedThingProvider.get(thing.getUID()) != null;
EnrichedThingDTO enrichedThingDTO = thing != null
? EnrichedThingDTOMapper.map(thing, thingStatusInfo, this.getThingFirmwareStatusInfo(thing.getUID()),
getLinkedItemsMap(thing), managed)
@ -666,89 +705,6 @@ public class ThingResource implements RESTResource {
return JSONResponse.createResponse(status, enrichedThingDTO, errormessage);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setItemChannelLinkRegistry(ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setItemFactory(ItemFactory itemFactory) {
this.itemFactory = itemFactory;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = itemRegistry;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setManagedItemChannelLinkProvider(ManagedItemChannelLinkProvider managedItemChannelLinkProvider) {
this.managedItemChannelLinkProvider = managedItemChannelLinkProvider;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setManagedItemProvider(ManagedItemProvider managedItemProvider) {
this.managedItemProvider = managedItemProvider;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setManagedThingProvider(ManagedThingProvider managedThingProvider) {
this.managedThingProvider = managedThingProvider;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setThingRegistry(ThingRegistry thingRegistry) {
this.thingRegistry = thingRegistry;
}
protected void unsetItemChannelLinkRegistry(ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = null;
}
protected void unsetItemFactory(ItemFactory itemFactory) {
this.itemFactory = null;
}
protected void unsetItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = null;
}
protected void unsetManagedItemChannelLinkProvider(ManagedItemChannelLinkProvider managedItemChannelLinkProvider) {
this.managedItemChannelLinkProvider = null;
}
protected void unsetManagedItemProvider(ManagedItemProvider managedItemProvider) {
this.managedItemProvider = null;
}
protected void unsetManagedThingProvider(ManagedThingProvider managedThingProvider) {
this.managedThingProvider = null;
}
protected void unsetThingRegistry(ThingRegistry thingRegistry) {
this.thingRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigStatusService(ConfigStatusService configStatusService) {
this.configStatusService = configStatusService;
}
protected void unsetConfigStatusService(ConfigStatusService configStatusService) {
this.configStatusService = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setThingStatusInfoI18nLocalizationService(
ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService) {
this.thingStatusInfoI18nLocalizationService = thingStatusInfoI18nLocalizationService;
}
protected void unsetThingStatusInfoI18nLocalizationService(
ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService) {
this.thingStatusInfoI18nLocalizationService = null;
}
private EnrichedThingDTO convertToEnrichedThingDTO(Thing thing, Locale locale) {
boolean managed = managedThingProvider.get(thing.getUID()) != null;
ThingStatusInfo thingStatusInfo = thingStatusInfoI18nLocalizationService.getLocalizedThingStatusInfo(thing,
@ -772,62 +728,8 @@ public class ThingResource implements RESTResource {
}
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) {
this.thingTypeRegistry = thingTypeRegistry;
}
protected void unsetThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) {
this.thingTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
}
protected void unsetChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
this.channelTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setFirmwareUpdateService(FirmwareUpdateService firmwareUpdateService) {
this.firmwareUpdateService = firmwareUpdateService;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setFirmwareRegistry(FirmwareRegistry firmwareRegistry) {
this.firmwareRegistry = firmwareRegistry;
}
protected void unsetFirmwareRegistry(FirmwareRegistry firmwareRegistry) {
this.firmwareRegistry = null;
}
protected void unsetFirmwareUpdateService(FirmwareUpdateService firmwareUpdateService) {
this.firmwareUpdateService = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setThingManager(ThingManager thingManager) {
this.thingManager = thingManager;
}
protected void unsetThingManager(ThingManager thingManager) {
this.thingManager = null;
}
private Map<String, Object> normalizeConfiguration(Map<String, Object> properties, ThingTypeUID thingTypeUID,
ThingUID thingUID) {
private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID) {
if (properties == null || properties.isEmpty()) {
return properties;
}
@ -845,7 +747,7 @@ public class ThingResource implements RESTResource {
configDescriptions.add(typeConfigDesc);
}
}
if (getConfigDescriptionURI(thingUID) != null) {
if (thingUID != null) {
ConfigDescription thingConfigDesc = configDescRegistry
.getConfigDescription(getConfigDescriptionURI(thingUID));
if (thingConfigDesc != null) {
@ -860,8 +762,8 @@ public class ThingResource implements RESTResource {
return ConfigUtil.normalizeTypes(properties, configDescriptions);
}
private Map<String, Object> normalizeConfiguration(Map<String, Object> properties, ChannelTypeUID channelTypeUID,
ChannelUID channelUID) {
private @Nullable Map<String, Object> normalizeConfiguration(Map<String, Object> properties,
ChannelTypeUID channelTypeUID, ChannelUID channelUID) {
if (properties == null || properties.isEmpty()) {
return properties;
}
@ -922,14 +824,4 @@ public class ThingResource implements RESTResource {
throw new BadRequestException("Invalid URI syntax: " + uriString);
}
}
@Override
public boolean isSatisfied() {
return itemChannelLinkRegistry != null && itemFactory != null && itemRegistry != null
&& managedItemChannelLinkProvider != null && managedItemProvider != null && managedThingProvider != null
&& thingRegistry != null && configStatusService != null && configDescRegistry != null
&& thingTypeRegistry != null && channelTypeRegistry != null && firmwareUpdateService != null
&& thingStatusInfoI18nLocalizationService != null && firmwareRegistry != null && localeService != null
&& thingManager != null;
}
}

View File

@ -13,6 +13,7 @@
package org.openhab.core.io.rest.core.internal.thing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
@ -28,6 +29,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigDescription;
@ -55,10 +57,9 @@ import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ThingType;
import org.openhab.core.thing.type.ThingTypeRegistry;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -94,6 +95,7 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired
@Path(ThingTypeResource.PATH_THING_TYPES)
@Api(ThingTypeResource.PATH_THING_TYPES)
@NonNullByDefault
public class ThingTypeResource implements RESTResource {
/** The URI path to this resource */
@ -101,56 +103,24 @@ public class ThingTypeResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(ThingTypeResource.class);
private ThingTypeRegistry thingTypeRegistry;
private ConfigDescriptionRegistry configDescriptionRegistry;
private ChannelTypeRegistry channelTypeRegistry;
private ChannelGroupTypeRegistry channelGroupTypeRegistry;
private final ChannelTypeRegistry channelTypeRegistry;
private final ChannelGroupTypeRegistry channelGroupTypeRegistry;
private final ConfigDescriptionRegistry configDescriptionRegistry;
private final LocaleService localeService;
private final ThingTypeRegistry thingTypeRegistry;
private LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) {
this.thingTypeRegistry = thingTypeRegistry;
}
protected void unsetThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) {
this.thingTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
@Activate
public ThingTypeResource( //
final @Reference ChannelTypeRegistry channelTypeRegistry,
final @Reference ChannelGroupTypeRegistry channelGroupTypeRegistry,
final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
final @Reference LocaleService localeService, //
final @Reference ThingTypeRegistry thingTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
}
protected void unsetChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
this.channelTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setChannelGroupTypeRegistry(ChannelGroupTypeRegistry channelGroupTypeRegistry) {
this.channelGroupTypeRegistry = channelGroupTypeRegistry;
}
protected void unsetChannelGroupTypeRegistry(ChannelGroupTypeRegistry channelGroupTypeRegistry) {
this.channelGroupTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.configDescriptionRegistry = configDescriptionRegistry;
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.thingTypeRegistry = thingTypeRegistry;
}
@GET
@ -159,11 +129,11 @@ public class ThingTypeResource implements RESTResource {
@ApiOperation(value = "Gets all available thing types without config description, channels and properties.", response = StrippedThingTypeDTO.class, responseContainer = "Set")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = StrippedThingTypeDTO.class, responseContainer = "Set"))
public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language,
@QueryParam("bindingId") @ApiParam(value = "filter by binding Id", required = false) @Nullable String bindingId) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("bindingId") @ApiParam(value = "filter by binding Id") @Nullable String bindingId) {
Locale locale = localeService.getLocale(language);
Stream<StrippedThingTypeDTO> typeStream = thingTypeRegistry.getThingTypes(locale).stream()
.map(t -> convertToStrippedThingTypeDTO(t, locale));
.map(thingType -> StrippedThingTypeDTOMapper.map(thingType, locale));
if (bindingId != null) {
typeStream = typeStream.filter(type -> type.UID.startsWith(bindingId + ':'));
@ -181,7 +151,7 @@ public class ThingTypeResource implements RESTResource {
@ApiResponse(code = 200, message = "Thing type with provided thingTypeUID does not exist.", response = ThingTypeDTO.class),
@ApiResponse(code = 404, message = "No content") })
public Response getByUID(@PathParam("thingTypeUID") @ApiParam(value = "thingTypeUID") String thingTypeUID,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
Locale locale = localeService.getLocale(language);
ThingType thingType = thingTypeRegistry.getThingType(new ThingTypeUID(thingTypeUID), locale);
if (thingType != null) {
@ -191,7 +161,7 @@ public class ThingTypeResource implements RESTResource {
}
}
private ThingTypeDTO convertToThingTypeDTO(ThingType thingType, Locale locale) {
private @Nullable ThingTypeDTO convertToThingTypeDTO(ThingType thingType, Locale locale) {
final ConfigDescription configDescription;
if (thingType.getConfigDescriptionURI() != null) {
configDescription = this.configDescriptionRegistry.getConfigDescription(thingType.getConfigDescriptionURI(),
@ -233,21 +203,21 @@ public class ThingTypeResource implements RESTResource {
ChannelGroupType channelGroupType = channelGroupTypeRegistry
.getChannelGroupType(channelGroupDefinition.getTypeUID(), locale);
// Default to the channelGroupDefinition label to override the
// channelGroupType
// Default to the channelGroupDefinition label/description to override the channelGroupType
String label = channelGroupDefinition.getLabel();
if (label == null) {
label = channelGroupType.getLabel();
}
// Default to the channelGroupDefinition description to override the
// channelGroupType
String description = channelGroupDefinition.getDescription();
if (description == null) {
description = channelGroupType.getDescription();
List<ChannelDefinition> channelDefinitions = Collections.emptyList();
if (channelGroupType != null) {
if (label == null) {
label = channelGroupType.getLabel();
}
if (description == null) {
description = channelGroupType.getDescription();
}
channelDefinitions = channelGroupType.getChannelDefinitions();
}
List<ChannelDefinition> channelDefinitions = channelGroupType.getChannelDefinitions();
List<ChannelDefinitionDTO> channelDefinitionDTOs = convertToChannelDefinitionDTOs(channelDefinitions,
locale);
@ -257,8 +227,8 @@ public class ThingTypeResource implements RESTResource {
return channelGroupDefinitionDTOs;
}
private List<ChannelDefinitionDTO> convertToChannelDefinitionDTOs(List<ChannelDefinition> channelDefinitions,
Locale locale) {
private @Nullable List<ChannelDefinitionDTO> convertToChannelDefinitionDTOs(
List<ChannelDefinition> channelDefinitions, Locale locale) {
List<ChannelDefinitionDTO> channelDefinitionDTOs = new ArrayList<>();
for (ChannelDefinition channelDefinition : channelDefinitions) {
ChannelType channelType = channelTypeRegistry.getChannelType(channelDefinition.getChannelTypeUID(), locale);
@ -289,21 +259,4 @@ public class ThingTypeResource implements RESTResource {
}
return channelDefinitionDTOs;
}
private StrippedThingTypeDTO convertToStrippedThingTypeDTO(ThingType thingType, Locale locale) {
final StrippedThingTypeDTO strippedThingTypeDTO = StrippedThingTypeDTOMapper.map(thingType, locale);
if (strippedThingTypeDTO != null) {
return strippedThingTypeDTO;
} else {
logger.warn("Cannot create DTO for thingType '{}'. Skip it.", thingType);
}
return null;
}
@Override
public boolean isSatisfied() {
return thingTypeRegistry != null && configDescriptionRegistry != null && channelTypeRegistry != null
&& channelGroupTypeRegistry != null && localeService != null;
}
}

View File

@ -14,7 +14,6 @@ package org.openhab.core.io.rest.core.internal.channel;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
@ -30,6 +29,7 @@ import org.hamcrest.core.IsCollectionContaining;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.config.core.ConfigDescriptionRegistry;
import org.openhab.core.io.rest.LocaleServiceImpl;
import org.openhab.core.thing.profiles.ProfileTypeRegistry;
import org.openhab.core.thing.profiles.ProfileTypeUID;
@ -46,25 +46,23 @@ public class ChannelTypeResourceTest {
private ChannelTypeResource channelTypeResource;
@Mock
private ChannelTypeRegistry channelTypeRegistry;
@Mock
private ProfileTypeRegistry profileTypeRegistry;
private @Mock ChannelTypeRegistry channelTypeRegistry;
private @Mock ConfigDescriptionRegistry configDescriptionRegistry;
private @Mock LocaleServiceImpl localeService;
private @Mock ProfileTypeRegistry profileTypeRegistry;
@Before
public void setup() {
initMocks(this);
channelTypeResource = new ChannelTypeResource();
channelTypeResource.setLocaleService(new LocaleServiceImpl());
channelTypeResource.setChannelTypeRegistry(channelTypeRegistry);
channelTypeResource.setProfileTypeRegistry(profileTypeRegistry);
channelTypeResource = new ChannelTypeResource(channelTypeRegistry, configDescriptionRegistry, localeService,
profileTypeRegistry);
}
@Test
public void getAllShouldRetrieveAllChannelTypes() throws Exception {
when(localeService.getLocale(null)).thenReturn(Locale.ENGLISH);
channelTypeResource.getAll(null, null);
verify(channelTypeRegistry).getChannelTypes(any(Locale.class));
verify(channelTypeRegistry).getChannelTypes(Locale.ENGLISH);
}
@SuppressWarnings("unchecked")

View File

@ -32,6 +32,8 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Component;
@ -62,6 +64,7 @@ import io.swagger.annotations.ApiResponses;
@Path(LogHandler.PATH_LOG)
@Api(LogHandler.PATH_LOG)
@Produces(MediaType.APPLICATION_JSON)
@NonNullByDefault
public class LogHandler implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(LogHandler.class);
@ -80,9 +83,9 @@ public class LogHandler implements RESTResource {
*/
public class LogMessage {
public long timestamp;
public String severity;
public URL url;
public String message;
public @Nullable String severity;
public @Nullable URL url;
public @Nullable String message;
}
@GET
@ -96,7 +99,8 @@ public class LogHandler implements RESTResource {
@ApiOperation(value = "Returns the last logged frontend messages. The amount is limited to the "
+ LogConstants.LOG_BUFFER_LIMIT + " last entries.")
@ApiParam(name = "limit", allowableValues = "range[1, " + LogConstants.LOG_BUFFER_LIMIT + "]")
public Response getLastLogs(@DefaultValue(LogConstants.LOG_BUFFER_LIMIT + "") @QueryParam("limit") Integer limit) {
public Response getLastLogs(
@DefaultValue(LogConstants.LOG_BUFFER_LIMIT + "") @QueryParam("limit") @Nullable Integer limit) {
if (logBuffer.isEmpty()) {
return Response.ok("[]").build();
}
@ -127,7 +131,7 @@ public class LogHandler implements RESTResource {
@ApiParam(name = "logMessage", value = "Severity is required and can be one of error, warn, info or debug, depending on activated severities which you can GET at /logLevels.", example = "{\"severity\": \"error\", \"url\": \"http://example.org\", \"message\": \"Error message\"}")
@ApiResponses({ @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 403, message = LogConstants.LOG_SEVERITY_IS_NOT_SUPPORTED) })
public Response log(final LogMessage logMessage) {
public Response log(final @Nullable LogMessage logMessage) {
if (logMessage == null) {
logger.debug("Received null log message model!");
return Response.status(500)
@ -155,7 +159,9 @@ public class LogHandler implements RESTResource {
* @return Falls if severity is not supported, true if successfully logged.
*/
private boolean doLog(LogMessage logMessage) {
switch (logMessage.severity.toLowerCase()) {
String severity = logMessage.severity;
severity = severity != null ? severity.toLowerCase() : "";
switch (severity) {
case "error":
logger.error(LogConstants.FRONTEND_LOG_PATTERN, logMessage.url, logMessage.message);
break;

View File

@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.events.Event;
import org.openhab.core.events.EventFilter;
@ -62,6 +63,7 @@ import org.slf4j.LoggerFactory;
*/
@Component(service = { SitemapSubscriptionService.class,
EventSubscriber.class }, configurationPid = "org.openhab.sitemapsubscription")
@NonNullByDefault
public class SitemapSubscriptionService implements ModelRepositoryChangeListener, EventSubscriber {
private static final String SITEMAP_PAGE_SEPARATOR = "#";
@ -77,7 +79,8 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
void onRelease(String subscriptionId);
}
private ItemUIRegistry itemUIRegistry;
private final ItemUIRegistry itemUIRegistry;
private final List<SitemapProvider> sitemapProviders = new ArrayList<>();
/* subscription id -> sitemap+page */
@ -95,12 +98,10 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
/* Max number of subscriptions at the same time */
private int maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS;
public SitemapSubscriptionService() {
}
@Activate
protected void activate(Map<String, Object> config) {
public SitemapSubscriptionService(Map<String, Object> config, final @Reference ItemUIRegistry itemUIRegistry) {
applyConfig(config);
this.itemUIRegistry = itemUIRegistry;
}
@Deactivate
@ -132,15 +133,6 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
}
}
@Reference
protected void setItemUIRegistry(ItemUIRegistry itemUIRegistry) {
this.itemUIRegistry = itemUIRegistry;
}
protected void unsetItemUIRegistry(ItemUIRegistry itemUIRegistry) {
this.itemUIRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addSitemapProvider(SitemapProvider provider) {
sitemapProviders.add(provider);
@ -158,7 +150,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
* @param callback an instance that should receive the events
* @returns a unique id that identifies the subscription or null if the limit of subscriptions is already reached
*/
public String createSubscription(SitemapSubscriptionCallback callback) {
public @Nullable String createSubscription(SitemapSubscriptionCallback callback) {
if (maxSubscriptions >= 0 && callbacks.size() >= maxSubscriptions) {
logger.debug("No new subscription delivered as limit ({}) is already reached", maxSubscriptions);
return null;
@ -206,7 +198,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
* @param subscriptionId the subscription to get the page id for
* @return the id of the currently active page or null if no page is currently set for the subscription
*/
public String getPageId(String subscriptionId) {
public @Nullable String getPageId(String subscriptionId) {
String sitemapWithPageId = pageOfSubscription.get(subscriptionId);
return (sitemapWithPageId == null) ? null : extractPageId(sitemapWithPageId);
}
@ -217,7 +209,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
* @param subscriptionId the subscription to get the sitemap name for
* @return the name of the current sitemap or null if no sitemap is currently set for the subscription
*/
public String getSitemapName(String subscriptionId) {
public @Nullable String getSitemapName(String subscriptionId) {
String sitemapWithPageId = pageOfSubscription.get(subscriptionId);
return (sitemapWithPageId == null) ? null : extractSitemapName(sitemapWithPageId);
}
@ -260,8 +252,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
// there is no listener for this page yet, so let's try to create one
listener = new PageChangeListener(sitemapName, pageId, itemUIRegistry, collectWidgets(sitemapName, pageId));
pageChangeListeners.put(getValue(sitemapName, pageId), listener);
}
if (listener != null) {
} else {
listener.addCallback(callback);
}
}
@ -301,7 +292,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
return sitemapName + SITEMAP_PAGE_SEPARATOR + pageId;
}
private Sitemap getSitemap(String sitemapName) {
private @Nullable Sitemap getSitemap(String sitemapName) {
for (SitemapProvider provider : sitemapProviders) {
Sitemap sitemap = provider.getSitemap(sitemapName);
if (sitemap != null) {

View File

@ -53,6 +53,7 @@ import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.io.rest.JSONResponse;
@ -128,6 +129,7 @@ import io.swagger.annotations.ApiResponses;
@Path(SitemapResource.PATH_SITEMAPS)
@RolesAllowed({ Role.USER, Role.ADMIN })
@Api(SitemapResource.PATH_SITEMAPS)
@NonNullByDefault
public class SitemapResource
implements RESTResource, SitemapSubscriptionCallback, SseBroadcaster.Listener<SseSinkInfo> {
@ -139,24 +141,27 @@ public class SitemapResource
private static final long TIMEOUT_IN_MS = 30000;
private @NonNullByDefault({}) Sse sse;
private SseBroadcaster<@NonNull SseSinkInfo> broadcaster;
@Context
@NonNullByDefault({})
UriInfo uriInfo;
@Context
@NonNullByDefault({})
HttpServletRequest request;
@Context
private HttpServletResponse response;
@NonNullByDefault({})
HttpServletResponse response;
private ItemUIRegistry itemUIRegistry;
@Context
@NonNullByDefault({})
Sse sse;
private SitemapSubscriptionService subscriptions;
private LocaleService localeService;
private final ItemUIRegistry itemUIRegistry;
private final SitemapSubscriptionService subscriptions;
private final LocaleService localeService;
private final java.util.List<SitemapProvider> sitemapProviders = new ArrayList<>();
@ -165,10 +170,17 @@ public class SitemapResource
private final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(ThreadPoolManager.THREAD_POOL_NAME_COMMON);
private ScheduledFuture<?> cleanSubscriptionsJob;
private @Nullable ScheduledFuture<?> cleanSubscriptionsJob;
@Activate
protected void activate() {
public SitemapResource( //
final @Reference ItemUIRegistry itemUIRegistry, //
final @Reference LocaleService localeService, //
final @Reference SitemapSubscriptionService subscriptions) {
this.itemUIRegistry = itemUIRegistry;
this.localeService = localeService;
this.subscriptions = subscriptions;
broadcaster = new SseBroadcaster<>();
// The clean SSE subscriptions job sends an ALIVE event to all subscribers. This will trigger
@ -179,45 +191,21 @@ public class SitemapResource
// The clean SSE subscriptions job is run every 5 minutes.
cleanSubscriptionsJob = scheduler.scheduleAtFixedRate(() -> {
logger.debug("Run clean SSE subscriptions job");
if (subscriptions != null) {
subscriptions.checkAliveClients();
}
subscriptions.checkAliveClients();
}, 1, 5, TimeUnit.MINUTES);
}
@Deactivate
protected void deactivate() {
if (cleanSubscriptionsJob != null && !cleanSubscriptionsJob.isCancelled()) {
ScheduledFuture<?> job = cleanSubscriptionsJob;
if (job != null && !job.isCancelled()) {
logger.debug("Cancel clean SSE subscriptions job");
cleanSubscriptionsJob.cancel(true);
job.cancel(true);
cleanSubscriptionsJob = null;
}
broadcaster.close();
}
@Context
public void setSse(final Sse sse) {
this.sse = sse;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
public void setItemUIRegistry(ItemUIRegistry itemUIRegistry) {
this.itemUIRegistry = itemUIRegistry;
}
public void unsetItemUIRegistry(ItemUIRegistry itemUIRegistry) {
this.itemUIRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
public void setSitemapSubscriptionService(SitemapSubscriptionService subscriptions) {
this.subscriptions = subscriptions;
}
public void unsetSitemapSubscriptionService(SitemapSubscriptionService subscriptions) {
this.subscriptions = null;
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
public void addSitemapProvider(SitemapProvider provider) {
sitemapProviders.add(provider);
@ -227,15 +215,6 @@ public class SitemapResource
sitemapProviders.remove(provider);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all available sitemaps.", response = SitemapDTO.class, responseContainer = "Collection")
@ -252,10 +231,10 @@ public class SitemapResource
@ApiOperation(value = "Get sitemap by name.", response = SitemapDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response getSitemapData(@Context HttpHeaders headers,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("sitemapname") @ApiParam(value = "sitemap name") String sitemapname,
@QueryParam("type") String type, @QueryParam("jsoncallback") @DefaultValue("callback") String callback,
@QueryParam("includeHidden") @ApiParam(value = "include hidden widgets", required = false) boolean includeHiddenWidgets) {
@QueryParam("includeHidden") @ApiParam(value = "include hidden widgets") boolean includeHiddenWidgets) {
final Locale locale = localeService.getLocale(language);
logger.debug("Received HTTP GET request from IP {} at '{}' for media type '{}'.", request.getRemoteAddr(),
uriInfo.getPath(), type);
@ -272,11 +251,11 @@ public class SitemapResource
@ApiResponse(code = 404, message = "Sitemap with requested name does not exist or page does not exist, or page refers to a non-linkable widget"),
@ApiResponse(code = 400, message = "Invalid subscription id has been provided.") })
public Response getPageData(@Context HttpHeaders headers,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("sitemapname") @ApiParam(value = "sitemap name") String sitemapname,
@PathParam("pageid") @ApiParam(value = "page id") String pageId,
@QueryParam("subscriptionid") @ApiParam(value = "subscriptionid", required = false) String subscriptionId,
@QueryParam("includeHidden") @ApiParam(value = "include hidden widgets", required = false) boolean includeHiddenWidgets) {
@QueryParam("subscriptionid") @ApiParam(value = "subscriptionid") @Nullable String subscriptionId,
@QueryParam("includeHidden") @ApiParam(value = "include hidden widgets") boolean includeHiddenWidgets) {
final Locale locale = localeService.getLocale(language);
logger.debug("Received HTTP GET request from IP {} at '{}'", request.getRemoteAddr(), uriInfo.getPath());
@ -345,8 +324,8 @@ public class SitemapResource
@ApiResponse(code = 404, message = "Subscription not found.") })
public void getSitemapEvents(@Context final SseEventSink sseEventSink, @Context final HttpServletResponse response,
@PathParam("subscriptionid") @ApiParam(value = "subscription id") String subscriptionId,
@QueryParam("sitemap") @ApiParam(value = "sitemap name", required = false) String sitemapname,
@QueryParam("pageid") @ApiParam(value = "page id", required = false) String pageId) {
@QueryParam("sitemap") @ApiParam(value = "sitemap name") @Nullable String sitemapname,
@QueryParam("pageid") @ApiParam(value = "page id") @Nullable String pageId) {
final SseSinkInfo sinkInfo = knownSubscriptions.get(subscriptionId);
if (sinkInfo == null) {
logger.debug("Subscription id {} does not exist.", subscriptionId);
@ -475,8 +454,9 @@ public class SitemapResource
return bean;
}
private PageDTO createPageBean(String sitemapName, String title, String icon, String pageId, EList<Widget> children,
boolean drillDown, boolean isLeaf, URI uri, Locale locale, boolean timeout, boolean includeHiddenWidgets) {
private PageDTO createPageBean(String sitemapName, @Nullable String title, @Nullable String icon, String pageId,
@Nullable EList<Widget> children, boolean drillDown, boolean isLeaf, URI uri, Locale locale,
boolean timeout, boolean includeHiddenWidgets) {
PageDTO bean = new PageDTO();
bean.timeout = timeout;
bean.id = pageId;
@ -499,8 +479,8 @@ public class SitemapResource
return bean;
}
private WidgetDTO createWidgetBean(String sitemapName, Widget widget, boolean drillDown, URI uri, String widgetId,
Locale locale, boolean evenIfHidden) {
private @Nullable WidgetDTO createWidgetBean(String sitemapName, Widget widget, boolean drillDown, URI uri,
String widgetId, Locale locale, boolean evenIfHidden) {
// Test visibility
if (!evenIfHidden && !itemUIRegistry.getVisiblity(widget)) {
return null;
@ -653,7 +633,7 @@ public class SitemapResource
return true;
}
private Sitemap getSitemap(String sitemapname) {
private @Nullable Sitemap getSitemap(String sitemapname) {
for (SitemapProvider provider : sitemapProviders) {
Sitemap sitemap = provider.getSitemap(sitemapname);
if (sitemap != null) {
@ -723,34 +703,32 @@ public class SitemapResource
*/
private Set<GenericItem> getAllItems(EList<Widget> widgets) {
Set<GenericItem> items = new HashSet<>();
if (itemUIRegistry != null) {
for (Widget widget : widgets) {
// We skip the chart widgets having a refresh argument
boolean skipWidget = false;
if (widget instanceof Chart) {
Chart chartWidget = (Chart) widget;
skipWidget = chartWidget.getRefresh() > 0;
}
String itemName = widget.getItem();
if (!skipWidget && itemName != null) {
try {
Item item = itemUIRegistry.getItem(itemName);
if (item instanceof GenericItem) {
items.add((GenericItem) item);
}
} catch (ItemNotFoundException e) {
// ignore
}
}
// Consider all items inside the frame
if (widget instanceof Frame) {
items.addAll(getAllItems(((Frame) widget).getChildren()));
}
// Consider items involved in any visibility, labelcolor and valuecolor condition
items.addAll(getItemsInVisibilityCond(widget.getVisibility()));
items.addAll(getItemsInColorCond(widget.getLabelColor()));
items.addAll(getItemsInColorCond(widget.getValueColor()));
for (Widget widget : widgets) {
// We skip the chart widgets having a refresh argument
boolean skipWidget = false;
if (widget instanceof Chart) {
Chart chartWidget = (Chart) widget;
skipWidget = chartWidget.getRefresh() > 0;
}
String itemName = widget.getItem();
if (!skipWidget && itemName != null) {
try {
Item item = itemUIRegistry.getItem(itemName);
if (item instanceof GenericItem) {
items.add((GenericItem) item);
}
} catch (ItemNotFoundException e) {
// ignore
}
}
// Consider all items inside the frame
if (widget instanceof Frame) {
items.addAll(getAllItems(((Frame) widget).getChildren()));
}
// Consider items involved in any visibility, labelcolor and valuecolor condition
items.addAll(getItemsInVisibilityCond(widget.getVisibility()));
items.addAll(getItemsInColorCond(widget.getLabelColor()));
items.addAll(getItemsInColorCond(widget.getValueColor()));
}
return items;
}
@ -858,11 +836,6 @@ public class SitemapResource
knownSubscriptions.remove(subscriptionId);
}
@Override
public boolean isSatisfied() {
return itemUIRegistry != null && subscriptions != null && localeService != null;
}
@Override
public void sseEventSinkRemoved(SseEventSink sink, SseSinkInfo info) {
logger.debug("SSE connection for subscription {} has been closed.", info.subscriptionId);

View File

@ -38,6 +38,7 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.io.rest.sitemap.SitemapSubscriptionService;
import org.openhab.core.items.GenericItem;
import org.openhab.core.items.ItemNotFoundException;
import org.openhab.core.library.types.DecimalType;
@ -79,23 +80,14 @@ public class SitemapResourceTest extends JavaTest {
private SitemapResource sitemapResource;
@Mock
private UriInfo uriInfo;
@Mock
private HttpServletRequest request;
@Mock
private SitemapProvider sitemapProvider;
@Mock
private Sitemap defaultSitemap;
@Mock
private ItemUIRegistry itemUIRegistry;
@Mock
private HttpHeaders headers;
private @Mock HttpHeaders headers;
private @Mock Sitemap defaultSitemap;
private @Mock ItemUIRegistry itemUIRegistry;
private @Mock LocaleService localeService;
private @Mock HttpServletRequest request;
private @Mock SitemapProvider sitemapProvider;
private @Mock SitemapSubscriptionService subscriptions;
private @Mock UriInfo uriInfo;
private GenericItem item;
private GenericItem visibilityRuleItem;
@ -107,7 +99,8 @@ public class SitemapResourceTest extends JavaTest {
@Before
public void setup() throws Exception {
initMocks(this);
sitemapResource = new SitemapResource();
sitemapResource = new SitemapResource(itemUIRegistry, localeService, subscriptions);
when(uriInfo.getAbsolutePathBuilder()).thenReturn(UriBuilder.fromPath(SITEMAP_PATH));
when(uriInfo.getBaseUriBuilder()).thenReturn(UriBuilder.fromPath(SITEMAP_PATH));
@ -121,9 +114,7 @@ public class SitemapResourceTest extends JavaTest {
labelColorItem = new TestItem(LABEL_COLOR_ITEM_NAME);
valueColorItem = new TestItem(VALUE_COLOR_ITEM_NAME);
LocaleService localeService = mock(LocaleService.class);
when(localeService.getLocale(null)).thenReturn(Locale.US);
sitemapResource.setLocaleService(localeService);
configureSitemapProviderMock();
configureSitemapMock();
@ -131,7 +122,6 @@ public class SitemapResourceTest extends JavaTest {
widgets = initSitemapWidgets();
configureItemUIRegistry(PercentType.HUNDRED, OnOffType.ON);
sitemapResource.setItemUIRegistry(itemUIRegistry);
// Disable long polling
when(headers.getRequestHeader(HTTP_HEADER_X_ATMOSPHERE_TRANSPORT)).thenReturn(null);

View File

@ -95,7 +95,7 @@ public class SseResource implements SsePublisher {
private final Logger logger = LoggerFactory.getLogger(SseResource.class);
private @NonNullByDefault({}) Sse sse;
private @Context @NonNullByDefault({}) Sse sse;
private final SseBroadcaster<SseSinkItemInfo> itemStatesBroadcaster = new SseBroadcaster<>();
private final SseItemStatesEventBuilder itemStatesEventBuilder;
@ -103,11 +103,6 @@ public class SseResource implements SsePublisher {
private ExecutorService executorService;
@Context
public void setSse(final Sse sse) {
this.sse = sse;
}
@Activate
public SseResource(@Reference SseItemStatesEventBuilder itemStatesEventBuilder) {
this.executorService = Executors.newSingleThreadExecutor();

View File

@ -23,12 +23,11 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
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.openhab.core.auth.Role;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
@ -39,10 +38,9 @@ import org.openhab.core.ui.components.UIComponentRegistry;
import org.openhab.core.ui.components.UIComponentRegistryFactory;
import org.openhab.core.ui.tiles.Tile;
import org.openhab.core.ui.tiles.TileProvider;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -67,16 +65,22 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired
@Path(UIResource.PATH_UI)
@Api(UIResource.PATH_UI)
@NonNullByDefault
public class UIResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_UI = "ui";
@Context
private UriInfo uriInfo;
private final UIComponentRegistryFactory componentRegistryFactory;
private final TileProvider tileProvider;
private TileProvider tileProvider;
private UIComponentRegistryFactory componentRegistryFactory;
@Activate
public UIResource( //
final @Reference UIComponentRegistryFactory componentRegistryFactory,
final @Reference TileProvider tileProvider) {
this.componentRegistryFactory = componentRegistryFactory;
this.tileProvider = tileProvider;
}
@GET
@Path("/tiles")
@ -169,29 +173,6 @@ public class UIResource implements RESTResource {
return Response.ok().build();
}
@Override
public boolean isSatisfied() {
return tileProvider != null && componentRegistryFactory != null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setTileProvider(TileProvider tileProvider) {
this.tileProvider = tileProvider;
}
protected void unsetTileProvider(TileProvider tileProvider) {
this.tileProvider = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setComponentRegistryFactory(UIComponentRegistryFactory componentRegistryFactory) {
this.componentRegistryFactory = componentRegistryFactory;
}
protected void unsetComponentRegistryFactory(UIComponentRegistryFactory componentRegistryFactory) {
this.componentRegistryFactory = null;
}
private TileDTO toTileDTO(Tile tile) {
return new TileDTO(tile.getName(), tile.getUrl(), tile.getOverlay(), tile.getImageUrl());
}

View File

@ -16,6 +16,7 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.voice.text.HumanLanguageInterpreter;
/**
@ -23,6 +24,7 @@ import org.openhab.core.voice.text.HumanLanguageInterpreter;
*
* @author Kai Kreuzer - Initial contribution
*/
@NonNullByDefault
public class HLIMapper {
/**

View File

@ -12,6 +12,7 @@
*/
package org.openhab.core.io.rest.voice.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.voice.Voice;
/**
@ -19,6 +20,7 @@ import org.openhab.core.voice.Voice;
*
* @author Laurent Garnier - Initial contribution
*/
@NonNullByDefault
public class VoiceMapper {
/**

View File

@ -12,10 +12,9 @@
*/
package org.openhab.core.io.rest.voice.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
@ -26,13 +25,13 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
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;
import org.openhab.core.auth.Role;
import org.openhab.core.io.rest.JSONResponse;
import org.openhab.core.io.rest.LocaleService;
@ -42,10 +41,9 @@ import org.openhab.core.voice.Voice;
import org.openhab.core.voice.VoiceManager;
import org.openhab.core.voice.text.HumanLanguageInterpreter;
import org.openhab.core.voice.text.InterpretationException;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -73,32 +71,21 @@ import io.swagger.annotations.ApiResponses;
@Path(VoiceResource.PATH_VOICE)
@RolesAllowed({ Role.USER, Role.ADMIN })
@Api(VoiceResource.PATH_VOICE)
@NonNullByDefault
public class VoiceResource implements RESTResource {
static final String PATH_VOICE = "voice";
/** The URI path to this resource */
public static final String PATH_VOICE = "voice";
@Context
UriInfo uriInfo;
private final LocaleService localeService;
private final VoiceManager voiceManager;
private VoiceManager voiceManager;
private LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
public void setVoiceManager(VoiceManager voiceManager) {
this.voiceManager = voiceManager;
}
public void unsetVoiceManager(VoiceManager voiceManager) {
this.voiceManager = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
@Activate
public VoiceResource( //
final @Reference LocaleService localeService, //
final @Reference VoiceManager voiceManager) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
this.voiceManager = voiceManager;
}
@GET
@ -107,13 +94,10 @@ public class VoiceResource implements RESTResource {
@ApiOperation(value = "Get the list of all interpreters.", response = HumanLanguageInterpreterDTO.class, responseContainer = "List")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response getInterpreters(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language) {
final Locale locale = localeService.getLocale(language);
Collection<HumanLanguageInterpreter> hlis = voiceManager.getHLIs();
List<HumanLanguageInterpreterDTO> dtos = new ArrayList<>(hlis.size());
for (HumanLanguageInterpreter hli : hlis) {
dtos.add(HLIMapper.map(hli, locale));
}
List<HumanLanguageInterpreterDTO> dtos = voiceManager.getHLIs().stream().map(hli -> HLIMapper.map(hli, locale))
.collect(Collectors.toList());
return Response.ok(dtos).build();
}
@ -124,16 +108,16 @@ public class VoiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Interpreter not found") })
public Response getInterpreter(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
@PathParam("id") @ApiParam(value = "interpreter id", required = true) String id) {
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("id") @ApiParam(value = "interpreter id") String id) {
final Locale locale = localeService.getLocale(language);
HumanLanguageInterpreter hli = voiceManager.getHLI(id);
if (hli != null) {
HumanLanguageInterpreterDTO dto = HLIMapper.map(hli, locale);
return Response.ok(dto).build();
} else {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Interpreter not found");
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "No interpreter found");
}
HumanLanguageInterpreterDTO dto = HLIMapper.map(hli, locale);
return Response.ok(dto).build();
}
@POST
@ -143,20 +127,21 @@ public class VoiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "No human language interpreter was found."),
@ApiResponse(code = 400, message = "interpretation exception occurs") })
public Response interpret(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
public Response interpret(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@ApiParam(value = "text to interpret", required = true) String text,
@PathParam("id") @ApiParam(value = "interpreter id", required = true) String id) {
@PathParam("id") @ApiParam(value = "interpreter id") String id) {
final Locale locale = localeService.getLocale(language);
HumanLanguageInterpreter hli = voiceManager.getHLI(id);
if (hli != null) {
try {
hli.interpret(locale, text);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} catch (InterpretationException e) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
}
} else {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Interpreter not found");
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "No interpreter found");
}
try {
hli.interpret(locale, text);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} catch (InterpretationException e) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
}
}
@ -167,20 +152,21 @@ public class VoiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "No human language interpreter was found."),
@ApiResponse(code = 400, message = "interpretation exception occurs") })
public Response interpret(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language,
public Response interpret(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@ApiParam(value = "text to interpret", required = true) String text) {
final Locale locale = localeService.getLocale(language);
HumanLanguageInterpreter hli = voiceManager.getHLI();
if (hli != null) {
try {
hli.interpret(locale, text);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} catch (InterpretationException e) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
}
} else {
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "No interpreter found");
}
try {
hli.interpret(locale, text);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} catch (InterpretationException e) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
}
}
@GET
@ -189,11 +175,7 @@ public class VoiceResource implements RESTResource {
@ApiOperation(value = "Get the list of all voices.", response = VoiceDTO.class, responseContainer = "List")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response getVoices() {
Collection<Voice> voices = voiceManager.getAllVoices();
List<VoiceDTO> dtos = new ArrayList<>(voices.size());
for (Voice voice : voices) {
dtos.add(VoiceMapper.map(voice));
}
List<VoiceDTO> dtos = voiceManager.getAllVoices().stream().map(VoiceMapper::map).collect(Collectors.toList());
return Response.ok(dtos).build();
}
@ -205,12 +187,12 @@ public class VoiceResource implements RESTResource {
@ApiResponse(code = 404, message = "No default voice was found.") })
public Response getDefaultVoice() {
Voice voice = voiceManager.getDefaultVoice();
if (voice != null) {
VoiceDTO dto = VoiceMapper.map(voice);
return Response.ok(dto).build();
} else {
if (voice == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Default voice not found");
}
VoiceDTO dto = VoiceMapper.map(voice);
return Response.ok(dto).build();
}
@POST
@ -219,14 +201,9 @@ public class VoiceResource implements RESTResource {
@ApiOperation(value = "Speaks a given text with a given voice through the given audio sink.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response say(@ApiParam(value = "text to speak", required = true) String text,
@ApiParam(value = "voice id", required = false) @QueryParam("voiceid") String voiceId,
@ApiParam(value = "audio sink id", required = false) @QueryParam("sinkid") String sinkId) {
@QueryParam("voiceid") @ApiParam(value = "voice id") @Nullable String voiceId,
@QueryParam("sinkid") @ApiParam(value = "audio sink id") @Nullable String sinkId) {
voiceManager.say(text, voiceId, sinkId);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
}
@Override
public boolean isSatisfied() {
return voiceManager != null && localeService != null;
}
}

View File

@ -12,20 +12,15 @@
*/
package org.openhab.core.io.rest;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* This is a marker interface for REST resource implementations
*
* @author Kai Kreuzer - Initial contribution
* @author Stefan Triller - Added default implementation for isSatisfied
*/
@NonNullByDefault
public interface RESTResource {
/**
* Method used to determine availability of a RESTResource
*
* @return true if this RESTResource is ready to process requests, false otherwise.
*/
default boolean isSatisfied() {
return true;
}
}

View File

@ -1,62 +0,0 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB 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.openhab.core.io.rest.internal.filter;
import java.io.IOException;
import java.util.List;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsExtension;
/**
* A filter that only affects resources implementing the {@link SatisfiableRESTResource} interface.
* If the current request is going to be fulfilled by a Resource implementing this interface and the
* {@link SatisfiableRESTResource#isSatisfied()} returns false then the request will be aborted with HTTP Status Code
* 503 - Service Unavailable.
*
* @author Ivan Iliev - Initial contribution
* @author Markus Rathgeb - Migrated to JAX-RS Whiteboard Specification
*/
@Component
@JaxrsExtension
@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")")
public class SatisfiableResourceFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
UriInfo uriInfo = ctx.getUriInfo();
if (uriInfo != null) {
List<Object> matchedResources = uriInfo.getMatchedResources();
if (matchedResources != null && !matchedResources.isEmpty()) {
// current resource is always first as per documentation
Object matchedResource = matchedResources.get(0);
if (matchedResource instanceof RESTResource && !((RESTResource) matchedResource).isSatisfied()) {
ctx.abortWith(Response.status(Status.SERVICE_UNAVAILABLE).build());
}
}
}
}
}

View File

@ -1,93 +0,0 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB 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.openhab.core.io.rest.internal.filter;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.*;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.openhab.core.io.rest.RESTResource;
/**
* Test for {@link SatisfiableResourceFilter}
*
* @author Ivan Iliev - Initial contribution
* @author Wouter Born - Migrate tests from Groovy to Java and use Mockito
*/
public class SatisfiableResourceFilterTest {
private @Mock ContainerRequestContext context;
private @Mock UriInfo uriInfo;
private @Mock RESTResource resource;
public @Rule MockitoRule mockitoRule = MockitoJUnit.rule();
private SatisfiableResourceFilter filter = new SatisfiableResourceFilter();
@Before
public void before() {
when(context.getUriInfo()).thenReturn(uriInfo);
}
@Test
public void testWithBasicRESTResource() throws IOException {
when(uriInfo.getMatchedResources()).thenReturn(singletonList(new RESTResource() {
}));
filter.filter(context);
verify(context, never()).abortWith(isA(Response.class));
verify(uriInfo).getMatchedResources();
}
@Test
public void testWithSatisfiableRESTResourceSatisfied() throws IOException {
when(uriInfo.getMatchedResources()).thenReturn(singletonList(resource));
when(resource.isSatisfied()).thenReturn(true);
filter.filter(context);
verify(context, never()).abortWith(isA(Response.class));
verify(uriInfo).getMatchedResources();
verify(resource, atLeastOnce()).isSatisfied();
}
@Test
public void testWithSatisfiableRESTResourceNOTSatisfied() throws IOException {
when(uriInfo.getMatchedResources()).thenReturn(singletonList(resource));
when(resource.isSatisfied()).thenReturn(false);
filter.filter(context);
ArgumentCaptor<Response> captor = ArgumentCaptor.forClass(Response.class);
verify(context, times(1)).abortWith(captor.capture());
assertEquals(Status.SERVICE_UNAVAILABLE.getStatusCode(), captor.getValue().getStatus());
verify(uriInfo).getMatchedResources();
verify(resource, atLeastOnce()).isSatisfied();
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.core.thing.profiles.dto;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.profiles.ProfileType;
import org.openhab.core.thing.profiles.TriggerProfileType;
@ -21,6 +22,7 @@ import org.openhab.core.thing.profiles.TriggerProfileType;
*
* @author Stefan Triller - Initial contribution
*/
@NonNullByDefault
public class ProfileTypeDTOMapper {
/**

View File

@ -20,16 +20,17 @@ import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
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.ui.icon.IconProvider;
import org.openhab.core.ui.icon.IconSet;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
@ -42,6 +43,7 @@ import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
@ -58,14 +60,20 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired
@Path(IconSetResource.PATH_ICONSETS)
@Api(IconSetResource.PATH_ICONSETS)
@NonNullByDefault
public class IconSetResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_ICONSETS = "iconsets";
private List<IconProvider> iconProviders = new ArrayList<>(5);
private final List<IconProvider> iconProviders = new ArrayList<>(5);
private LocaleService localeService;
private final LocaleService localeService;
@Activate
public IconSetResource(final @Reference LocaleService localeService) {
this.localeService = localeService;
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addIconProvider(IconProvider iconProvider) {
@ -76,23 +84,11 @@ public class IconSetResource implements RESTResource {
this.iconProviders.remove(iconProvider);
}
@Reference
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService;
}
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@Context
UriInfo uriInfo;
@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets all icon sets.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response getAll(@HeaderParam("Accept-Language") String language) {
public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language) {
Locale locale = localeService.getLocale(language);
List<IconSet> iconSets = new ArrayList<>(iconProviders.size());

View File

@ -14,13 +14,15 @@ package org.openhab.core.io.rest.core.internal.discovery;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.config.core.ConfigDescriptionRegistry;
import org.openhab.core.config.discovery.inbox.Inbox;
import org.openhab.core.test.java.JavaOSGiTest;
@ -41,32 +43,32 @@ public class InboxResourceOSGITest extends JavaOSGiTest {
private final Thing testThing = ThingBuilder.create(testTypeUID, testUID).build();
private final String testThingLabel = "dummy_thing";
private @Mock Inbox inbox;
@Before
public void setup() throws Exception {
ConfigDescriptionRegistry configDescRegistry = getService(ConfigDescriptionRegistry.class);
assertFalse(configDescRegistry == null);
initMocks(this);
registerService(new InboxResource(), InboxResource.class.getName());
ConfigDescriptionRegistry configDescRegistry = getService(ConfigDescriptionRegistry.class);
assertNotNull(configDescRegistry);
registerService(new InboxResource(inbox), InboxResource.class.getName());
resource = getService(InboxResource.class);
assertFalse(resource == null);
assertNotNull(resource);
}
@Test
public void assertThatApproveApprovesThingsWhichAreInTheInbox() {
Inbox inbox = mock(Inbox.class);
when(inbox.approve(any(), any())).thenReturn(testThing);
resource.setInbox(inbox);
Response reponse = resource.approve(null, testThing.getUID().toString(), testThingLabel);
assertTrue(reponse.getStatusInfo().getStatusCode() == Status.OK.getStatusCode());
}
@Test
public void assertThatApproveDoesntApproveThingsWhichAreNotInTheInbox() {
Inbox inbox = mock(Inbox.class);
when(inbox.approve(any(), any())).thenThrow(new IllegalArgumentException());
resource.setInbox(inbox);
Response reponse = resource.approve(null, testThing.getUID().toString(), testThingLabel);
assertTrue(reponse.getStatusInfo().getStatusCode() == Status.NOT_FOUND.getStatusCode());
}

View File

@ -51,6 +51,7 @@ import org.openhab.core.library.items.DimmerItem;
import org.openhab.core.library.items.StringItem;
import org.openhab.core.library.items.SwitchItem;
import org.openhab.core.test.java.JavaOSGiTest;
import org.openhab.core.test.storage.VolatileStorageService;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
@ -72,8 +73,7 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
private GenericItem item3;
private GenericItem item4;
@Mock
private ItemProvider itemProvider;
private @Mock ItemProvider itemProvider;
private UriInfo uriInfo;
private HttpHeaders httpHeaders;
@ -85,6 +85,8 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
public void setup() {
initMocks(this);
registerService(new VolatileStorageService());
itemResource = getService(RESTResource.class, ItemResource.class);
assertNotNull(itemResource);

View File

@ -15,6 +15,7 @@ package org.openhab.core.io.rest.core.internal.persistence;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.ArrayList;
import java.util.Date;
@ -23,7 +24,10 @@ import java.util.TimeZone;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.persistence.HistoricItem;
import org.openhab.core.persistence.PersistenceServiceRegistry;
@ -44,9 +48,16 @@ public class PersistenceResourceTest {
private PersistenceResource pResource;
private List<HistoricItem> items;
private @Mock ItemRegistry itemRegistry;
private @Mock LocaleService localeService;
private @Mock PersistenceServiceRegistry persistenceServiceRegistry;
private @Mock TimeZoneProvider timeZoneProvider;
@Before
public void setup() {
pResource = new PersistenceResource();
initMocks(this);
pResource = new PersistenceResource(itemRegistry, localeService, persistenceServiceRegistry, timeZoneProvider);
int startValue = 2016;
int endValue = 2018;
@ -78,20 +89,12 @@ public class PersistenceResourceTest {
QueryablePersistenceService pService = mock(QueryablePersistenceService.class);
when(pService.query(any())).thenReturn(items);
TimeZoneProvider timeZoneProvider = mock(TimeZoneProvider.class);
when(persistenceServiceRegistry.get(PERSISTENCE_SERVICE_ID)).thenReturn(pService);
when(timeZoneProvider.getTimeZone()).thenReturn(TimeZone.getDefault().toZoneId());
PersistenceServiceRegistry pServiceRegistry = mock(PersistenceServiceRegistry.class);
when(pServiceRegistry.get(PERSISTENCE_SERVICE_ID)).thenReturn(pService);
pResource.setPersistenceServiceRegistry(pServiceRegistry);
pResource.setTimeZoneProvider(timeZoneProvider);
}
@Test
public void testGetPersistenceItemData() {
// pResource.httpGetPersistenceItemData(headers, serviceId, itemName, startTime, endTime, pageNumber,
// pageLength, boundary)
ItemHistoryDTO dto = pResource.createDTO(PERSISTENCE_SERVICE_ID, "testItem", null, null, 1, 5, false);
assertEquals(5, Integer.parseInt(dto.datapoints));

View File

@ -15,7 +15,8 @@ package org.openhab.core.io.rest.core.internal.profile;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.ArrayList;
import java.util.List;
@ -24,6 +25,8 @@ import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.io.rest.LocaleService;
import org.openhab.core.test.java.JavaTest;
import org.openhab.core.thing.profiles.ProfileType;
import org.openhab.core.thing.profiles.ProfileTypeBuilder;
@ -42,7 +45,7 @@ import org.openhab.core.thing.type.ChannelTypeUID;
*/
public class ProfileTypeResourceTest extends JavaTest {
private ProfileTypeResource ressource;
private ProfileTypeResource resource;
// UIDs for state profile types
private final ProfileTypeUID stateProfileTypeUID1 = new ProfileTypeUID("my:stateProfile1");
@ -67,12 +70,15 @@ public class ProfileTypeResourceTest extends JavaTest {
private final ChannelType otherTriggerChannelType = ChannelTypeBuilder
.trigger(otherTriggerChannelTypeUID, "channel1").build();
private @Mock ChannelTypeRegistry channelTypeRegistry;
private @Mock LocaleService localeService;
private @Mock ProfileTypeRegistry profileTypeRegistry;
@Before
public void setup() {
ressource = new ProfileTypeResource();
initMocks(this);
ChannelTypeRegistry ctRegistry = mock(ChannelTypeRegistry.class);
ProfileTypeRegistry ptRegistry = mock(ProfileTypeRegistry.class);
resource = new ProfileTypeResource(channelTypeRegistry, localeService, profileTypeRegistry);
List<ProfileType> profileTypes = new ArrayList<>();
ProfileType pt1 = ProfileTypeBuilder.newState(stateProfileTypeUID1, "profile1")
@ -87,20 +93,17 @@ public class ProfileTypeResourceTest extends JavaTest {
profileTypes.add(pt3);
profileTypes.add(pt4);
when(ptRegistry.getProfileTypes(any())).thenReturn(profileTypes);
when(ctRegistry.getChannelType(pt1ChannelType1UID, null)).thenReturn(pt1ChannelType1);
when(ctRegistry.getChannelType(pt3ChannelType1UID, null)).thenReturn(pt3ChannelType1);
when(profileTypeRegistry.getProfileTypes(any())).thenReturn(profileTypes);
when(channelTypeRegistry.getChannelType(pt1ChannelType1UID, null)).thenReturn(pt1ChannelType1);
when(channelTypeRegistry.getChannelType(pt3ChannelType1UID, null)).thenReturn(pt3ChannelType1);
when(ctRegistry.getChannelType(otherStateChannelTypeUID, null)).thenReturn(otherStateChannelType);
when(ctRegistry.getChannelType(otherTriggerChannelTypeUID, null)).thenReturn(otherTriggerChannelType);
ressource.setChannelTypeRegistry(ctRegistry);
ressource.setProfileTypeRegistry(ptRegistry);
when(channelTypeRegistry.getChannelType(otherStateChannelTypeUID, null)).thenReturn(otherStateChannelType);
when(channelTypeRegistry.getChannelType(otherTriggerChannelTypeUID, null)).thenReturn(otherTriggerChannelType);
}
@Test
public void testGetAll() {
Stream<ProfileTypeDTO> result = ressource.getProfileTypes(null, null, null);
Stream<ProfileTypeDTO> result = resource.getProfileTypes(null, null, null);
List<ProfileTypeDTO> list = result.collect(Collectors.toList());
assertThat(list.size(), is(4));
@ -108,7 +111,7 @@ public class ProfileTypeResourceTest extends JavaTest {
@Test
public void testGetProfileTypesForStateChannel1() {
Stream<ProfileTypeDTO> result = ressource.getProfileTypes(null, pt1ChannelType1UID.toString(), null);
Stream<ProfileTypeDTO> result = resource.getProfileTypes(null, pt1ChannelType1UID.toString(), null);
List<ProfileTypeDTO> list = result.collect(Collectors.toList());
// should be both state profiles because the second state profile supports ALL item types on the channel side
@ -121,7 +124,7 @@ public class ProfileTypeResourceTest extends JavaTest {
@Test
public void testGetProfileTypesForOtherChannel() {
Stream<ProfileTypeDTO> result = ressource.getProfileTypes(null, otherStateChannelTypeUID.toString(), null);
Stream<ProfileTypeDTO> result = resource.getProfileTypes(null, otherStateChannelTypeUID.toString(), null);
List<ProfileTypeDTO> list = result.collect(Collectors.toList());
// should be only the second state profile because the first one is restricted to another item type on the
@ -136,7 +139,7 @@ public class ProfileTypeResourceTest extends JavaTest {
@Test
public void testGetProfileTypesForTriggerChannel1() {
Stream<ProfileTypeDTO> result = ressource.getProfileTypes(null, pt3ChannelType1UID.toString(), null);
Stream<ProfileTypeDTO> result = resource.getProfileTypes(null, pt3ChannelType1UID.toString(), null);
List<ProfileTypeDTO> list = result.collect(Collectors.toList());
// should be both trigger profiles because the second trigger profile supports ALL channel types
@ -149,7 +152,7 @@ public class ProfileTypeResourceTest extends JavaTest {
@Test
public void testGetProfileTypesForTriggerChannel2() {
Stream<ProfileTypeDTO> result = ressource.getProfileTypes(null, otherTriggerChannelTypeUID.toString(), null);
Stream<ProfileTypeDTO> result = resource.getProfileTypes(null, otherTriggerChannelTypeUID.toString(), null);
List<ProfileTypeDTO> list = result.collect(Collectors.toList());
// should be only the second trigger profile because the first one is restricted to another channel type UID