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.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; 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.LocaleService;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -82,28 +79,15 @@ public class ModuleTypeResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_MODULE_TYPES = "module-types"; public static final String PATH_MODULE_TYPES = "module-types";
private @NonNullByDefault({}) ModuleTypeRegistry moduleTypeRegistry; private final LocaleService localeService;
private @NonNullByDefault({}) LocaleService localeService; private final ModuleTypeRegistry moduleTypeRegistry;
@Context @Activate
private @NonNullByDefault({}) UriInfo uriInfo; public ModuleTypeResource( //
final @Reference LocaleService localeService, //
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference ModuleTypeRegistry moduleTypeRegistry) {
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) {
this.localeService = localeService; this.localeService = localeService;
} this.moduleTypeRegistry = moduleTypeRegistry;
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
} }
@GET @GET
@ -112,8 +96,8 @@ public class ModuleTypeResource implements RESTResource {
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ModuleTypeDTO.class, responseContainer = "List") }) @ApiResponse(code = 200, message = "OK", response = ModuleTypeDTO.class, responseContainer = "List") })
public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language, 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("tags") @ApiParam(value = "tags for filtering") @Nullable String tagList,
@QueryParam("type") @ApiParam(value = "filtering by action, condition or trigger", required = false) @Nullable String type) { @QueryParam("type") @ApiParam(value = "filtering by action, condition or trigger") @Nullable String type) {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
final String[] tags = tagList != null ? tagList.split(",") : new String[0]; final String[] tags = tagList != null ? tagList.split(",") : new String[0];
final List<ModuleTypeDTO> modules = new ArrayList<>(); 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), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ModuleTypeDTO.class),
@ApiResponse(code = 404, message = "Module Type corresponding to the given UID does not found.") }) @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, 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); Locale locale = localeService.getLocale(language);
final ModuleType moduleType = moduleTypeRegistry.get(moduleTypeUID, locale); final ModuleType moduleType = moduleTypeRegistry.get(moduleTypeUID, locale);
if (moduleType != null) { if (moduleType != null) {
@ -168,9 +152,4 @@ public class ModuleTypeResource implements RESTResource {
String.format("Cannot handle given module type class (%s)", moduleType.getClass())); 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.Response.Status;
import javax.ws.rs.core.UriInfo; 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.auth.Role;
import org.openhab.core.automation.Action; import org.openhab.core.automation.Action;
import org.openhab.core.automation.Condition; 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.JSONResponse;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -98,6 +99,7 @@ import io.swagger.annotations.ResponseHeader;
@Path(RuleResource.PATH_RULES) @Path(RuleResource.PATH_RULES)
@Api(RuleResource.PATH_RULES) @Api(RuleResource.PATH_RULES)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@NonNullByDefault
public class RuleResource implements RESTResource { public class RuleResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
@ -105,28 +107,17 @@ public class RuleResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(RuleResource.class); private final Logger logger = LoggerFactory.getLogger(RuleResource.class);
private RuleRegistry ruleRegistry; private final RuleManager ruleManager;
private RuleManager ruleManager; private final RuleRegistry ruleRegistry;
@Context private @Context @NonNullByDefault({}) UriInfo uriInfo;
private UriInfo uriInfo;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) @Activate
protected void setRuleRegistry(RuleRegistry ruleRegistry) { public RuleResource( //
this.ruleRegistry = ruleRegistry; final @Reference RuleManager ruleManager, //
} final @Reference RuleRegistry ruleRegistry) {
protected void unsetRuleRegistry(RuleRegistry ruleRegistry) {
this.ruleRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setRuleManager(RuleManager ruleManager) {
this.ruleManager = ruleManager; this.ruleManager = ruleManager;
} this.ruleRegistry = ruleRegistry;
protected void unsetRuleManager(RuleManager ruleManager) {
this.ruleManager = null;
} }
@GET @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") @ApiOperation(value = "Get available rules, optionally filtered by tags and/or prefix.", response = EnrichedRuleDTO.class, responseContainer = "Collection")
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = EnrichedRuleDTO.class, responseContainer = "Collection") }) @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 // match all
Predicate<Rule> p = r -> true; Predicate<Rule> p = r -> true;
// prefix parameter has been used // prefix parameter has been used
if (null != prefix) { if (prefix != null) {
// works also for null prefix // works also for null prefix
// (empty prefix used if searching for rules without prefix) // (empty prefix used if searching for rules without prefix)
p = p.and(hasPrefix(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) @ApiOperation(value = "Gets the rule corresponding to the given UID.", response = EnrichedRuleDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = EnrichedRuleDTO.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = EnrichedRuleDTO.class),
@ApiResponse(code = 404, message = "Rule not found") }) @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); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
return Response.ok(EnrichedRuleDTOMapper.map(rule, ruleManager)).build(); 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.") @ApiOperation(value = "Removes an existing rule corresponding to the given UID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", 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.") }) @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); Rule removedRule = ruleRegistry.remove(ruleUID);
if (removedRule == null) { if (removedRule == null) {
logger.info("Received HTTP DELETE request at '{}' for the unknown rule '{}'.", uriInfo.getPath(), ruleUID); 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.") @ApiOperation(value = "Updates an existing rule corresponding to the given UID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @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 { @ApiParam(value = "rule data", required = true) RuleDTO rule) throws IOException {
rule.uid = ruleUID; rule.uid = ruleUID;
final Rule oldRule = ruleRegistry.update(RuleDTOMapper.map(rule)); final Rule oldRule = ruleRegistry.update(RuleDTOMapper.map(rule));
@ -235,7 +227,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the rule configuration values.") @ApiOperation(value = "Gets the rule configuration values.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", 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.") }) @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 { throws IOException {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule == null) { if (rule == null) {
@ -253,8 +245,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Sets the rule configuration values.") @ApiOperation(value = "Sets the rule configuration values.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") })
public Response updateConfiguration( public Response updateConfiguration(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID,
@ApiParam(value = "config") Map<String, Object> configurationParameters) throws IOException { @ApiParam(value = "config") Map<String, Object> configurationParameters) throws IOException {
Map<String, Object> config = ConfigUtil.normalizeTypes(configurationParameters); Map<String, Object> config = ConfigUtil.normalizeTypes(configurationParameters);
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
@ -275,7 +266,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Sets the rule enabled status.") @ApiOperation(value = "Sets the rule enabled status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @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 { @ApiParam(value = "enable", required = true) String enabled) throws IOException {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule == null) { if (rule == null) {
@ -295,8 +286,7 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Executes actions of the rule.") @ApiOperation(value = "Executes actions of the rule.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @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) public Response runNow(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID) throws IOException {
throws IOException {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule == null) { if (rule == null) {
logger.info("Received HTTP PUT request for run now at '{}' for the unknown rule '{}'.", uriInfo.getPath(), 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 = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = TriggerDTO.class, responseContainer = "List"), @ApiResponse(code = 200, message = "OK", response = TriggerDTO.class, responseContainer = "List"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @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); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
return Response.ok(TriggerDTOMapper.map(rule.getTriggers())).build(); return Response.ok(TriggerDTOMapper.map(rule.getTriggers())).build();
@ -331,7 +321,7 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ConditionDTO.class, responseContainer = "List"), @ApiResponse(code = 200, message = "OK", response = ConditionDTO.class, responseContainer = "List"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @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); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
return Response.ok(ConditionDTOMapper.map(rule.getConditions())).build(); return Response.ok(ConditionDTOMapper.map(rule.getConditions())).build();
@ -347,7 +337,7 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ActionDTO.class, responseContainer = "List"), @ApiResponse(code = 200, message = "OK", response = ActionDTO.class, responseContainer = "List"),
@ApiResponse(code = 404, message = "Rule corresponding to the given UID does not found.") }) @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); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
return Response.ok(ActionDTOMapper.map(rule.getActions())).build(); 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) @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), @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.") }) @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, public Response getModuleById(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory, @PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("id") @ApiParam(value = "id", required = true) String id) { @PathParam("id") @ApiParam(value = "id") String id) {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
final ModuleDTO dto = getModuleDTO(rule, moduleCategory, id); final ModuleDTO dto = getModuleDTO(rule, moduleCategory, id);
@ -381,9 +371,9 @@ public class RuleResource implements RESTResource {
@ApiOperation(value = "Gets the module's configuration.") @ApiOperation(value = "Gets the module's configuration.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", 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.") }) @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, public Response getModuleConfig(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory, @PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("id") @ApiParam(value = "id", required = true) String id) { @PathParam("id") @ApiParam(value = "id") String id) {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
Module module = getModule(rule, moduleCategory, id); 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) @ApiOperation(value = "Gets the module's configuration parameter.", response = String.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", 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.") }) @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( public Response getModuleConfigParam(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID, @PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory, @PathParam("id") @ApiParam(value = "id") String id,
@PathParam("id") @ApiParam(value = "id", required = true) String id, @PathParam("param") @ApiParam(value = "param") String param) {
@PathParam("param") @ApiParam(value = "param", required = true) String param) {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
Module module = getModule(rule, moduleCategory, id); Module module = getModule(rule, moduleCategory, id);
@ -421,11 +410,10 @@ public class RuleResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @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.") }) @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) @Consumes(MediaType.TEXT_PLAIN)
public Response setModuleConfigParam( public Response setModuleConfigParam(@PathParam("ruleUID") @ApiParam(value = "ruleUID") String ruleUID,
@PathParam("ruleUID") @ApiParam(value = "ruleUID", required = true) String ruleUID, @PathParam("moduleCategory") @ApiParam(value = "moduleCategory") String moduleCategory,
@PathParam("moduleCategory") @ApiParam(value = "moduleCategory", required = true) String moduleCategory, @PathParam("id") @ApiParam(value = "id") String id,
@PathParam("id") @ApiParam(value = "id", required = true) String id, @PathParam("param") @ApiParam(value = "param") String param,
@PathParam("param") @ApiParam(value = "param", required = true) String param,
@ApiParam(value = "value", required = true) String value) { @ApiParam(value = "value", required = true) String value) {
Rule rule = ruleRegistry.get(ruleUID); Rule rule = ruleRegistry.get(ruleUID);
if (rule != null) { if (rule != null) {
@ -441,10 +429,7 @@ public class RuleResource implements RESTResource {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} }
protected <T extends Module> T getModuleById(final Collection<T> coll, final String id) { protected <T extends Module> @Nullable T getModuleById(final Collection<T> coll, final String id) {
if (coll == null) {
return null;
}
for (final T module : coll) { for (final T module : coll) {
if (module.getId().equals(id)) { if (module.getId().equals(id)) {
return module; return module;
@ -453,19 +438,19 @@ public class RuleResource implements RESTResource {
return null; return null;
} }
protected Trigger getTrigger(Rule rule, String id) { protected @Nullable Trigger getTrigger(Rule rule, String id) {
return getModuleById(rule.getTriggers(), 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); 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); 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)) { if ("triggers".equals(moduleCategory)) {
return getTrigger(rule, id); return getTrigger(rule, id);
} else if ("conditions".equals(moduleCategory)) { } 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)) { if ("triggers".equals(moduleCategory)) {
final Trigger trigger = getTrigger(rule, id); final Trigger trigger = getTrigger(rule, id);
return trigger == null ? null : TriggerDTOMapper.map(trigger); return trigger == null ? null : TriggerDTOMapper.map(trigger);
@ -491,9 +476,4 @@ public class RuleResource implements RESTResource {
return null; 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.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; 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.RuleTemplateDTO;
import org.openhab.core.automation.dto.RuleTemplateDTOMapper; import org.openhab.core.automation.dto.RuleTemplateDTOMapper;
import org.openhab.core.automation.template.RuleTemplate; 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.LocaleService;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -72,28 +70,15 @@ public class TemplateResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_TEMPLATES = "templates"; public static final String PATH_TEMPLATES = "templates";
private @NonNullByDefault({}) TemplateRegistry<@NonNull RuleTemplate> templateRegistry; private final LocaleService localeService;
private @NonNullByDefault({}) LocaleService localeService; private final TemplateRegistry<@NonNull RuleTemplate> templateRegistry;
@Context @Activate
private @NonNullByDefault({}) UriInfo uriInfo; public TemplateResource( //
final @Reference LocaleService localeService,
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference TemplateRegistry<@NonNull RuleTemplate> templateRegistry) {
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) {
this.localeService = localeService; this.localeService = localeService;
} this.templateRegistry = templateRegistry;
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
} }
@GET @GET
@ -101,7 +86,7 @@ public class TemplateResource implements RESTResource {
@ApiOperation(value = "Get all available templates.", response = Template.class, responseContainer = "Collection") @ApiOperation(value = "Get all available templates.", response = Template.class, responseContainer = "Collection")
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = Template.class, responseContainer = "Collection") }) @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); Locale locale = localeService.getLocale(language);
Collection<RuleTemplateDTO> result = templateRegistry.getAll(locale).stream() Collection<RuleTemplateDTO> result = templateRegistry.getAll(locale).stream()
.map(template -> RuleTemplateDTOMapper.map(template)).collect(Collectors.toList()); .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) @ApiOperation(value = "Gets a template corresponding to the given UID.", response = Template.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", 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.") }) @ApiResponse(code = 404, message = "Template corresponding to the given UID does not found.") })
public Response getByUID(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language, public Response getByUID(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@PathParam("templateUID") @ApiParam(value = "templateUID", required = true) String templateUID) { @PathParam("templateUID") @ApiParam(value = "templateUID") String templateUID) {
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
RuleTemplate template = templateRegistry.get(templateUID, locale); RuleTemplate template = templateRegistry.get(templateUID, locale);
if (template != null) { if (template != null) {
@ -124,9 +109,4 @@ public class TemplateResource implements RESTResource {
return Response.status(Status.NOT_FOUND).build(); 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; package org.openhab.core.automation.dto;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.template.RuleTemplate; import org.openhab.core.automation.template.RuleTemplate;
import org.openhab.core.config.core.dto.ConfigDescriptionDTOMapper; 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 * @author Ana Dimova - Initial contribution
*/ */
@NonNullByDefault
public class RuleTemplateDTOMapper { public class RuleTemplateDTOMapper {
public static RuleTemplateDTO map(final RuleTemplate template) { 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. * @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); this(properties == null ? emptyMap() : properties, false);
} }
@ -103,7 +103,7 @@ public class Configuration {
return properties.get(key); 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)); return properties.put(key, ConfigUtil.normalizeType(value, null));
} }
@ -150,7 +150,7 @@ public class Configuration {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(@Nullable Object obj) {
return (obj instanceof Configuration) && this.properties.equals(((Configuration) obj).properties); 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.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.auth.Role; import org.openhab.core.auth.Role;
import org.openhab.core.id.InstanceUUID; import org.openhab.core.id.InstanceUUID;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
@ -47,6 +48,7 @@ import io.swagger.annotations.ApiResponses;
@Path(UUIDResource.PATH_UUID) @Path(UUIDResource.PATH_UUID)
@Api(UUIDResource.PATH_UUID) @Api(UUIDResource.PATH_UUID)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@NonNullByDefault
public class UUIDResource implements RESTResource { public class UUIDResource implements RESTResource {
public static final String PATH_UUID = "uuid"; 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.LocaleService;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -70,29 +69,20 @@ import io.swagger.annotations.ApiResponses;
@NonNullByDefault @NonNullByDefault
public class AudioResource implements RESTResource { 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 final AudioManager audioManager;
private @Nullable LocaleService localeService; private final LocaleService localeService;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) @Activate
public void setAudioManager(AudioManager audioManager) { public AudioResource( //
final @Reference AudioManager audioManager, //
final @Reference LocaleService localeService) {
this.audioManager = audioManager; 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; this.localeService = localeService;
} }
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@GET @GET
@Path("/sources") @Path("/sources")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -158,9 +148,4 @@ public class AudioResource implements RESTResource {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Sink not found"); 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.SecurityContext;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.jose4j.base64url.Base64Url; import org.jose4j.base64url.Base64Url;
import org.openhab.core.auth.ManagedUser; import org.openhab.core.auth.ManagedUser;
import org.openhab.core.auth.PendingToken; import org.openhab.core.auth.PendingToken;
@ -79,6 +80,7 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired @JSONRequired
@Path(TokenResource.PATH_AUTH) @Path(TokenResource.PATH_AUTH)
@Api(TokenResource.PATH_AUTH) @Api(TokenResource.PATH_AUTH)
@NonNullByDefault
public class TokenResource implements RESTResource { public class TokenResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(TokenResource.class); 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 */ /** The default lifetime of tokens in minutes before they expire */
public static final int TOKEN_LIFETIME = 60; public static final int TOKEN_LIFETIME = 60;
@Context private @Context @NonNullByDefault({}) UriInfo uriInfo;
private UriInfo uriInfo;
private UserRegistry userRegistry; private final UserRegistry userRegistry;
private JwtHelper jwtHelper; private final JwtHelper jwtHelper;
@Activate @Activate
public TokenResource(final @Reference UserRegistry userRegistry, final @Reference JwtHelper jwtHelper) { 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.Map.Entry;
import java.util.Set; import java.util.Set;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.ConfigConstants; import org.openhab.core.config.core.ConfigConstants;
import org.openhab.core.config.core.Configuration; import org.openhab.core.config.core.Configuration;
import org.osgi.framework.Constants; 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 * @return config or null if no config with the given config id exists
* @throws IOException if configuration can not be read * @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); org.osgi.service.cm.Configuration configuration = configurationAdmin.getConfiguration(configId, null);
Dictionary<String, Object> properties = configuration.getProperties(); Dictionary<String, Object> properties = configuration.getProperties();
return toConfiguration(properties); return toConfiguration(properties);
@ -161,7 +162,7 @@ public class ConfigurationService {
return oldConfiguration; return oldConfiguration;
} }
private Configuration toConfiguration(Dictionary<String, Object> dictionary) { private @Nullable Configuration toConfiguration(Dictionary<String, Object> dictionary) {
if (dictionary == null) { if (dictionary == null) {
return null; return null;
} }

View File

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

View File

@ -27,13 +27,13 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; 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.auth.Role;
import org.openhab.core.binding.BindingInfo; import org.openhab.core.binding.BindingInfo;
import org.openhab.core.binding.BindingInfoRegistry; 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.RESTResource;
import org.openhab.core.io.rest.Stream2JSONInputStream; import org.openhab.core.io.rest.Stream2JSONInputStream;
import org.openhab.core.io.rest.core.config.ConfigurationService; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -83,6 +82,7 @@ import io.swagger.annotations.ApiResponses;
@Path(BindingResource.PATH_BINDINGS) @Path(BindingResource.PATH_BINDINGS)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(BindingResource.PATH_BINDINGS) @Api(BindingResource.PATH_BINDINGS)
@NonNullByDefault
public class BindingResource implements RESTResource { public class BindingResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
@ -90,40 +90,30 @@ public class BindingResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(BindingResource.class); private final Logger logger = LoggerFactory.getLogger(BindingResource.class);
private ConfigurationService configurationService; private final BindingInfoRegistry bindingInfoRegistry;
private ConfigDescriptionRegistry configDescRegistry; private final ConfigurationService configurationService;
private final ConfigDescriptionRegistry configDescRegistry;
private final LocaleService localeService;
private BindingInfoRegistry bindingInfoRegistry; @Activate
public BindingResource( //
private LocaleService localeService; final @Reference BindingInfoRegistry bindingInfoRegistry,
final @Reference ConfigurationService configurationService,
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference ConfigDescriptionRegistry configDescRegistry,
protected void setBindingInfoRegistry(BindingInfoRegistry bindingInfoRegistry) { final @Reference LocaleService localeService) {
this.bindingInfoRegistry = bindingInfoRegistry; this.bindingInfoRegistry = bindingInfoRegistry;
} this.configurationService = configurationService;
this.configDescRegistry = configDescRegistry;
protected void unsetBindingInfoRegistry(BindingInfoRegistry bindingInfoRegistry) {
this.bindingInfoRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService; this.localeService = localeService;
} }
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@Context
UriInfo uriInfo;
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all bindings.", response = BindingInfoDTO.class, responseContainer = "Set") @ApiOperation(value = "Get all bindings.", response = BindingInfoDTO.class, responseContainer = "Set")
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = BindingInfoDTO.class, responseContainer = "Set") }) @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); final Locale locale = localeService.getLocale(language);
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(locale); 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), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Binding does not exist"), @ApiResponse(code = 404, message = "Binding does not exist"),
@ApiResponse(code = 500, message = "Configuration can not be read due to internal error") }) @ApiResponse(code = 500, message = "Configuration can not be read due to internal error") })
public Response getConfiguration( public Response getConfiguration(@PathParam("bindingId") @ApiParam(value = "service ID") String bindingId) {
@PathParam("bindingId") @ApiParam(value = "service ID", required = true) String bindingId) {
try { try {
String configId = getConfigId(bindingId); String configId = getConfigId(bindingId);
if (configId == null) { if (configId == null) {
@ -164,9 +153,8 @@ public class BindingResource implements RESTResource {
@ApiResponse(code = 204, message = "No old configuration"), @ApiResponse(code = 204, message = "No old configuration"),
@ApiResponse(code = 404, message = "Binding does not exist"), @ApiResponse(code = 404, message = "Binding does not exist"),
@ApiResponse(code = 500, message = "Configuration can not be updated due to internal error") }) @ApiResponse(code = 500, message = "Configuration can not be updated due to internal error") })
public Response updateConfiguration( public Response updateConfiguration(@PathParam("bindingId") @ApiParam(value = "service ID") String bindingId,
@PathParam("bindingId") @ApiParam(value = "service ID", required = true) String bindingId, @Nullable Map<String, Object> configuration) {
Map<String, Object> configuration) {
try { try {
String configId = getConfigId(bindingId); String configId = getConfigId(bindingId);
if (configId == null) { 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()) { if (properties == null || properties.isEmpty()) {
return properties; return properties;
} }
@ -202,7 +191,7 @@ public class BindingResource implements RESTResource {
return ConfigUtil.normalizeTypes(properties, Collections.singletonList(configDesc)); return ConfigUtil.normalizeTypes(properties, Collections.singletonList(configDesc));
} }
private String getConfigId(String bindingId) { private @Nullable String getConfigId(String bindingId) {
BindingInfo bindingInfo = this.bindingInfoRegistry.getBindingInfo(bindingId); BindingInfo bindingInfo = this.bindingInfoRegistry.getBindingInfo(bindingId);
if (bindingInfo != null) { if (bindingInfo != null) {
return bindingInfo.getServiceId(); return bindingInfo.getServiceId();
@ -216,28 +205,4 @@ public class BindingResource implements RESTResource {
return new BindingInfoDTO(bindingInfo.getUID(), bindingInfo.getName(), bindingInfo.getAuthor(), return new BindingInfoDTO(bindingInfo.getUID(), bindingInfo.getName(), bindingInfo.getAuthor(),
bindingInfo.getDescription(), configDescriptionURI != null ? configDescriptionURI.toString() : null); 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;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role; import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigDescription; 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.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry; import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ChannelTypeUID; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -84,52 +84,27 @@ import io.swagger.annotations.ApiResponses;
@Path(ChannelTypeResource.PATH_CHANNEL_TYPES) @Path(ChannelTypeResource.PATH_CHANNEL_TYPES)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(ChannelTypeResource.PATH_CHANNEL_TYPES) @Api(ChannelTypeResource.PATH_CHANNEL_TYPES)
@NonNullByDefault
public class ChannelTypeResource implements RESTResource { public class ChannelTypeResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_CHANNEL_TYPES = "channel-types"; public static final String PATH_CHANNEL_TYPES = "channel-types";
private ChannelTypeRegistry channelTypeRegistry; private final ChannelTypeRegistry channelTypeRegistry;
private ConfigDescriptionRegistry configDescriptionRegistry; private final ConfigDescriptionRegistry configDescriptionRegistry;
private final LocaleService localeService;
private final ProfileTypeRegistry profileTypeRegistry;
private ProfileTypeRegistry profileTypeRegistry; @Activate
public ChannelTypeResource( //
private LocaleService localeService; final @Reference ChannelTypeRegistry channelTypeRegistry,
final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference LocaleService localeService, //
protected void setChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) { final @Reference ProfileTypeRegistry profileTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry; 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; 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; this.localeService = localeService;
} this.profileTypeRegistry = profileTypeRegistry;
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
} }
@GET @GET
@ -137,8 +112,8 @@ public class ChannelTypeResource implements RESTResource {
@ApiOperation(value = "Gets all available channel types.", response = ChannelTypeDTO.class, responseContainer = "Set") @ApiOperation(value = "Gets all available channel types.", response = ChannelTypeDTO.class, responseContainer = "Set")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ChannelTypeDTO.class, responseContainer = "Set")) @ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ChannelTypeDTO.class, responseContainer = "Set"))
public Response getAll( public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language, @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')", required = false) @Nullable String prefixes) { @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); Locale locale = localeService.getLocale(language);
Stream<ChannelTypeDTO> channelStream = channelTypeRegistry.getChannelTypes(locale).stream() 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 = 200, message = "Channel type with provided channelTypeUID does not exist.", response = ChannelTypeDTO.class),
@ApiResponse(code = 404, message = "No content") }) @ApiResponse(code = 404, message = "No content") })
public Response getByUID(@PathParam("channelTypeUID") @ApiParam(value = "channelTypeUID") String channelTypeUID, 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); Locale locale = localeService.getLocale(language);
ChannelType channelType = channelTypeRegistry.getChannelType(new ChannelTypeUID(channelTypeUID), locale); ChannelType channelType = channelTypeRegistry.getChannelType(new ChannelTypeUID(channelTypeUID), locale);
if (channelType != null) { if (channelType != null) {
@ -235,10 +210,4 @@ public class ChannelTypeResource implements RESTResource {
parameterGroups, channelType.getState(), channelType.getTags(), channelType.isAdvanced(), parameterGroups, channelType.getState(), channelType.getTags(), channelType.isAdvanced(),
channelType.getCommandDescription()); 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.RESTResource;
import org.openhab.core.io.rest.Stream2JSONInputStream; import org.openhab.core.io.rest.Stream2JSONInputStream;
import org.openhab.core.io.rest.core.config.EnrichedConfigDescriptionDTOMapper; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -78,26 +77,23 @@ public class ConfigDescriptionResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_CONFIG_DESCRIPTIONS = "config-descriptions"; 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; @Activate
public ConfigDescriptionResource( //
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
protected void setLocaleService(LocaleService localeService) { final @Reference LocaleService localeService) {
this.configDescriptionRegistry = configDescriptionRegistry;
this.localeService = localeService; this.localeService = localeService;
} }
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
}
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets all available config descriptions.", response = ConfigDescriptionDTO.class, responseContainer = "List") @ApiOperation(value = "Gets all available config descriptions.", response = ConfigDescriptionDTO.class, responseContainer = "List")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ConfigDescriptionDTO.class, responseContainer = "List")) @ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ConfigDescriptionDTO.class, responseContainer = "List"))
public Response getAll( public Response getAll(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language, //
@HeaderParam("Accept-Language") @ApiParam(value = "Accept-Language") @Nullable String language, // @QueryParam("scheme") @ApiParam(value = "scheme filter") @Nullable String scheme) {
@QueryParam("scheme") @ApiParam(value = "scheme filter", required = false) @Nullable String scheme) {
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
Collection<ConfigDescription> configDescriptions = configDescriptionRegistry.getConfigDescriptions(locale); Collection<ConfigDescription> configDescriptions = configDescriptionRegistry.getConfigDescriptions(locale);
return Response.ok(new Stream2JSONInputStream(configDescriptions.stream().filter(configDescription -> { 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) @ApiOperation(value = "Gets a config description by URI.", response = ConfigDescriptionDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", 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") }) @ApiResponse(code = 400, message = "Invalid URI syntax"), @ApiResponse(code = 404, message = "Not found") })
public Response getByURI( public Response getByURI(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@HeaderParam("Accept-Language") @ApiParam(value = "Accept-Language") @Nullable String language,
@PathParam("uri") @ApiParam(value = "uri") String uri) { @PathParam("uri") @ApiParam(value = "uri") String uri) {
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
URI uriObject = UriBuilder.fromPath(uri).build(); URI uriObject = UriBuilder.fromPath(uri).build();
@ -121,18 +116,4 @@ public class ConfigDescriptionResource implements RESTResource {
? Response.ok(EnrichedConfigDescriptionDTOMapper.map(configDescription)).build() ? Response.ok(EnrichedConfigDescriptionDTOMapper.map(configDescription)).build()
: JSONResponse.createErrorResponse(Status.NOT_FOUND, "Configuration not found: " + uri); : 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.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; 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.auth.Role;
import org.openhab.core.config.discovery.DiscoveryServiceRegistry; import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
import org.openhab.core.config.discovery.ScanListener; import org.openhab.core.config.discovery.ScanListener;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -68,6 +67,7 @@ import io.swagger.annotations.ApiResponses;
@Path(DiscoveryResource.PATH_DISCOVERY) @Path(DiscoveryResource.PATH_DISCOVERY)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(DiscoveryResource.PATH_DISCOVERY) @Api(DiscoveryResource.PATH_DISCOVERY)
@NonNullByDefault
public class DiscoveryResource implements RESTResource { public class DiscoveryResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
@ -75,20 +75,13 @@ public class DiscoveryResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(DiscoveryResource.class); private final Logger logger = LoggerFactory.getLogger(DiscoveryResource.class);
private DiscoveryServiceRegistry discoveryServiceRegistry; private final DiscoveryServiceRegistry discoveryServiceRegistry;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) @Activate
protected void setDiscoveryServiceRegistry(DiscoveryServiceRegistry discoveryServiceRegistry) { public DiscoveryResource(final @Reference DiscoveryServiceRegistry discoveryServiceRegistry) {
this.discoveryServiceRegistry = discoveryServiceRegistry; this.discoveryServiceRegistry = discoveryServiceRegistry;
} }
protected void unsetDiscoveryServiceRegistry(DiscoveryServiceRegistry discoveryServiceRegistry) {
this.discoveryServiceRegistry = null;
}
@Context
private UriInfo uriInfo;
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets all bindings that support discovery.", response = String.class, responseContainer = "Set") @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) { public Response scan(@PathParam("bindingId") @ApiParam(value = "bindingId") final String bindingId) {
discoveryServiceRegistry.startScan(bindingId, new ScanListener() { discoveryServiceRegistry.startScan(bindingId, new ScanListener() {
@Override @Override
public void onErrorOccurred(Exception exception) { public void onErrorOccurred(@Nullable Exception exception) {
logger.error("Error occurred while scanning for binding '{}': {}", bindingId, exception.getMessage(), logger.error("Error occurred while scanning for binding '{}'", bindingId, exception);
exception);
} }
@Override @Override
@ -120,9 +112,4 @@ public class DiscoveryResource implements RESTResource {
return Response.ok(discoveryServiceRegistry.getMaxScanTimeout(bindingId)).build(); 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.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; 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.auth.Role;
import org.openhab.core.config.discovery.DiscoveryResultFlag; import org.openhab.core.config.discovery.DiscoveryResultFlag;
import org.openhab.core.config.discovery.dto.DiscoveryResultDTO; 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.io.rest.Stream2JSONInputStream;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingUID; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -78,26 +77,20 @@ import io.swagger.annotations.ApiResponses;
@Path(InboxResource.PATH_INBOX) @Path(InboxResource.PATH_INBOX)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(InboxResource.PATH_INBOX) @Api(InboxResource.PATH_INBOX)
@NonNullByDefault
public class InboxResource implements RESTResource { public class InboxResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(InboxResource.class); private final Logger logger = LoggerFactory.getLogger(InboxResource.class);
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_INBOX = "inbox"; public static final String PATH_INBOX = "inbox";
private Inbox inbox; private final Inbox inbox;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) @Activate
protected void setInbox(Inbox inbox) { public InboxResource(final @Reference Inbox inbox) {
this.inbox = inbox; this.inbox = inbox;
} }
protected void unsetInbox(Inbox inbox) {
this.inbox = null;
}
@Context
private UriInfo uriInfo;
@POST @POST
@Path("/{thingUID}/approve") @Path("/{thingUID}/approve")
@Consumes(MediaType.TEXT_PLAIN) @Consumes(MediaType.TEXT_PLAIN)
@ -105,9 +98,10 @@ public class InboxResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Thing unable to be approved."), @ApiResponse(code = 404, message = "Thing unable to be approved."),
@ApiResponse(code = 409, message = "No binding found that supports this thing.") }) @ApiResponse(code = 409, message = "No binding found that supports this thing.") })
public Response approve(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language, public Response approve(
@PathParam("thingUID") @ApiParam(value = "thingUID", required = true) String thingUID, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@ApiParam(value = "thing label") String label) { @PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@ApiParam(value = "thing label") @Nullable String label) {
ThingUID thingUIDObject = new ThingUID(thingUID); ThingUID thingUIDObject = new ThingUID(thingUID);
String notEmptyLabel = label != null && !label.isEmpty() ? label : null; String notEmptyLabel = label != null && !label.isEmpty() ? label : null;
Thing thing = null; Thing thing = null;
@ -131,7 +125,7 @@ public class InboxResource implements RESTResource {
@ApiOperation(value = "Removes the discovery result from the inbox.") @ApiOperation(value = "Removes the discovery result from the inbox.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Discovery result not found in the inbox.") }) @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))) { if (inbox.remove(new ThingUID(thingUID))) {
return Response.ok(null, MediaType.TEXT_PLAIN).build(); return Response.ok(null, MediaType.TEXT_PLAIN).build();
} else { } else {
@ -152,7 +146,7 @@ public class InboxResource implements RESTResource {
@Path("/{thingUID}/ignore") @Path("/{thingUID}/ignore")
@ApiOperation(value = "Flags a discovery result as ignored for further processing.") @ApiOperation(value = "Flags a discovery result as ignored for further processing.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) @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); inbox.setFlag(new ThingUID(thingUID), DiscoveryResultFlag.IGNORED);
return Response.ok(null, MediaType.TEXT_PLAIN).build(); return Response.ok(null, MediaType.TEXT_PLAIN).build();
} }
@ -161,13 +155,8 @@ public class InboxResource implements RESTResource {
@Path("/{thingUID}/unignore") @Path("/{thingUID}/unignore")
@ApiOperation(value = "Removes ignore flag from a discovery result.") @ApiOperation(value = "Removes ignore flag from a discovery result.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) @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); inbox.setFlag(new ThingUID(thingUID), DiscoveryResultFlag.NEW);
return Response.ok(null, MediaType.TEXT_PLAIN).build(); 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.Response.Status;
import javax.ws.rs.core.UriInfo; 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.auth.Role;
import org.openhab.core.common.ThreadPoolManager; import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.events.Event; 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.RESTConstants;
import org.openhab.core.io.rest.RESTResource; import org.openhab.core.io.rest.RESTResource;
import org.openhab.core.io.rest.Stream2JSONInputStream; 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.Component;
import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferenceCardinality;
@ -81,6 +84,7 @@ import io.swagger.annotations.ApiResponses;
@Path(ExtensionResource.PATH_EXTENSIONS) @Path(ExtensionResource.PATH_EXTENSIONS)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(ExtensionResource.PATH_EXTENSIONS) @Api(ExtensionResource.PATH_EXTENSIONS)
@NonNullByDefault
public class ExtensionResource implements RESTResource { public class ExtensionResource implements RESTResource {
private static final String THREAD_POOL_NAME = "extensionService"; private static final String THREAD_POOL_NAME = "extensionService";
@ -88,12 +92,18 @@ public class ExtensionResource implements RESTResource {
public static final String PATH_EXTENSIONS = "extensions"; public static final String PATH_EXTENSIONS = "extensions";
private final Logger logger = LoggerFactory.getLogger(ExtensionResource.class); private final Logger logger = LoggerFactory.getLogger(ExtensionResource.class);
private final Set<ExtensionService> extensionServices = new CopyOnWriteArraySet<>(); 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) @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addExtensionService(ExtensionService featureService) { protected void addExtensionService(ExtensionService featureService) {
@ -104,32 +114,12 @@ public class ExtensionResource implements RESTResource {
this.extensionServices.remove(featureService); 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 @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all extensions.") @ApiOperation(value = "Get all extensions.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class) }) @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()); logger.debug("Received HTTP GET request at '{}'", uriInfo.getPath());
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
return Response.ok(new Stream2JSONInputStream(getAllExtensions(locale))).build(); return Response.ok(new Stream2JSONInputStream(getAllExtensions(locale))).build();
@ -140,7 +130,7 @@ public class ExtensionResource implements RESTResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all extension types.") @ApiOperation(value = "Get all extension types.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class) }) @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()); logger.debug("Received HTTP GET request at '{}'", uriInfo.getPath());
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
Stream<ExtensionType> extensionTypeStream = getAllExtensionTypes(locale).stream().distinct(); Stream<ExtensionType> extensionTypeStream = getAllExtensionTypes(locale).stream().distinct();
@ -153,8 +143,8 @@ public class ExtensionResource implements RESTResource {
@ApiOperation(value = "Get extension with given ID.") @ApiOperation(value = "Get extension with given ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Not found") }) @ApiResponse(code = 404, message = "Not found") })
public Response getById(@HeaderParam("Accept-Language") @ApiParam(value = "language") String language, public Response getById(@HeaderParam("Accept-Language") @ApiParam(value = "language") @Nullable String language,
@PathParam("extensionId") @ApiParam(value = "extension ID", required = true) String extensionId) { @PathParam("extensionId") @ApiParam(value = "extension ID") String extensionId) {
logger.debug("Received HTTP GET request at '{}'.", uriInfo.getPath()); logger.debug("Received HTTP GET request at '{}'.", uriInfo.getPath());
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
ExtensionService extensionService = getExtensionService(extensionId); ExtensionService extensionService = getExtensionService(extensionId);
@ -171,7 +161,7 @@ public class ExtensionResource implements RESTResource {
@ApiOperation(value = "Installs the extension with the given ID.") @ApiOperation(value = "Installs the extension with the given ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response installExtension( 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(() -> { ThreadPoolManager.getPool(THREAD_POOL_NAME).submit(() -> {
try { try {
ExtensionService extensionService = getExtensionService(extensionId); ExtensionService extensionService = getExtensionService(extensionId);
@ -190,7 +180,7 @@ public class ExtensionResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 400, message = "The given URL is malformed or not valid.") }) @ApiResponse(code = 400, message = "The given URL is malformed or not valid.") })
public Response installExtensionByURL( 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 { try {
URI extensionURI = new URI(url); URI extensionURI = new URI(url);
String extensionId = getExtensionId(extensionURI); String extensionId = getExtensionId(extensionURI);
@ -208,7 +198,7 @@ public class ExtensionResource implements RESTResource {
@ApiOperation(value = "Uninstalls the extension with the given ID.") @ApiOperation(value = "Uninstalls the extension with the given ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response uninstallExtension( 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(() -> { ThreadPoolManager.getPool(THREAD_POOL_NAME).submit(() -> {
try { try {
ExtensionService extensionService = getExtensionService(extensionId); ExtensionService extensionService = getExtensionService(extensionId);
@ -222,16 +212,9 @@ public class ExtensionResource implements RESTResource {
} }
private void postFailureEvent(String extensionId, String msg) { private void postFailureEvent(String extensionId, String msg) {
if (eventPublisher != null) {
Event event = ExtensionEventFactory.createExtensionFailureEvent(extensionId, msg); Event event = ExtensionEventFactory.createExtensionFailureEvent(extensionId, msg);
eventPublisher.post(event); eventPublisher.post(event);
} }
}
@Override
public boolean isSatisfied() {
return !extensionServices.isEmpty() && localeService != null;
}
private Stream<Extension> getAllExtensions(Locale locale) { private Stream<Extension> getAllExtensions(Locale locale) {
return extensionServices.stream().map(s -> s.getExtensions(locale)).flatMap(l -> l.stream()); return extensionServices.stream().map(s -> s.getExtensions(locale)).flatMap(l -> l.stream());

View File

@ -79,10 +79,9 @@ import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Command; import org.openhab.core.types.Command;
import org.openhab.core.types.State; import org.openhab.core.types.State;
import org.openhab.core.types.TypeParser; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; 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 final Logger logger = LoggerFactory.getLogger(ItemResource.class);
private @NonNullByDefault({}) ItemRegistry itemRegistry; private final DTOMapper dtoMapper;
private @NonNullByDefault({}) MetadataRegistry metadataRegistry; private final EventPublisher eventPublisher;
private @NonNullByDefault({}) EventPublisher eventPublisher; private final ItemBuilderFactory itemBuilderFactory;
private @NonNullByDefault({}) ManagedItemProvider managedItemProvider; private final ItemRegistry itemRegistry;
private @NonNullByDefault({}) DTOMapper dtoMapper; private final LocaleService localeService;
private @NonNullByDefault({}) MetadataSelectorMatcher metadataSelectorMatcher; private final ManagedItemProvider managedItemProvider;
private @NonNullByDefault({}) ItemBuilderFactory itemBuilderFactory; private final MetadataRegistry metadataRegistry;
private @NonNullByDefault({}) LocaleService localeService; private final MetadataSelectorMatcher metadataSelectorMatcher;
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) @Activate
protected void setItemRegistry(ItemRegistry itemRegistry) { public ItemResource(//
this.itemRegistry = itemRegistry; final @Reference DTOMapper dtoMapper, //
} final @Reference EventPublisher eventPublisher, //
final @Reference ItemBuilderFactory itemBuilderFactory, //
protected void unsetItemRegistry(ItemRegistry itemRegistry) { final @Reference ItemRegistry itemRegistry, //
this.itemRegistry = null; final @Reference LocaleService localeService, //
} final @Reference ManagedItemProvider managedItemProvider,
final @Reference MetadataRegistry metadataRegistry,
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference MetadataSelectorMatcher metadataSelectorMatcher) {
protected void setMetadataRegistry(MetadataRegistry metadataRegistry) { this.dtoMapper = dtoMapper;
this.metadataRegistry = metadataRegistry;
}
protected void unsetMetadataRegistry(MetadataRegistry metadataRegistry) {
this.metadataRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher; 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; this.itemBuilderFactory = itemBuilderFactory;
} this.itemRegistry = itemRegistry;
this.localeService = localeService;
public void unsetItemBuilderFactory(ItemBuilderFactory itemBuilderFactory) { this.managedItemProvider = managedItemProvider;
this.itemBuilderFactory = null; this.metadataRegistry = metadataRegistry;
this.metadataSelectorMatcher = metadataSelectorMatcher;
} }
private UriBuilder uriBuilder(final UriInfo uriInfo, final HttpHeaders httpHeaders) { 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") }) @ApiResponse(code = 200, message = "OK", response = EnrichedItemDTO.class, responseContainer = "List") })
public Response getItems(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders, public Response getItems(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("type") @ApiParam(value = "item type filter", required = false) @Nullable String type, @QueryParam("type") @ApiParam(value = "item type filter") @Nullable String type,
@QueryParam("tags") @ApiParam(value = "item tag filter", required = false) @Nullable String tags, @QueryParam("tags") @ApiParam(value = "item tag filter") @Nullable String tags,
@QueryParam("metadata") @ApiParam(value = "metadata selector", required = false) @Nullable String namespaceSelector, @QueryParam("metadata") @ApiParam(value = "metadata selector") @Nullable String namespaceSelector,
@DefaultValue("false") @QueryParam("recursive") @ApiParam(value = "get member items recursively", required = false) boolean recursive, @DefaultValue("false") @QueryParam("recursive") @ApiParam(value = "get member items recursively") boolean recursive,
@QueryParam("fields") @ApiParam(value = "limit output to the given fields (comma separated)", required = false) @Nullable String fields) { @QueryParam("fields") @ApiParam(value = "limit output to the given fields (comma separated)") @Nullable String fields) {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
final Set<String> namespaces = splitAndFilterNamespaces(namespaceSelector, locale); final Set<String> namespaces = splitAndFilterNamespaces(namespaceSelector, locale);
@ -276,8 +223,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 404, message = "Item not found") }) @ApiResponse(code = 404, message = "Item not found") })
public Response getItemData(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders, public Response getItemData(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("metadata") @ApiParam(value = "metadata selector", required = false) @Nullable String namespaceSelector, @QueryParam("metadata") @ApiParam(value = "metadata selector") @Nullable String namespaceSelector,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname) { @PathParam("itemname") @ApiParam(value = "item name") String itemname) {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
final Set<String> namespaces = splitAndFilterNamespaces(namespaceSelector, locale); final Set<String> namespaces = splitAndFilterNamespaces(namespaceSelector, locale);
@ -311,8 +258,7 @@ public class ItemResource implements RESTResource {
@ApiOperation(value = "Gets the state of an item.") @ApiOperation(value = "Gets the state of an item.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Item not found") }) @ApiResponse(code = 404, message = "Item not found") })
public Response getPlainItemState( public Response getPlainItemState(@PathParam("itemname") @ApiParam(value = "item name") String itemname) {
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname) {
// get item // get item
Item item = getItem(itemname); Item item = getItem(itemname);
@ -335,8 +281,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 404, message = "Item not found"), @ApiResponse(code = 404, message = "Item not found"),
@ApiResponse(code = 400, message = "Item state null") }) @ApiResponse(code = 400, message = "Item state null") })
public Response putItemState( public Response putItemState(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname, @PathParam("itemname") @ApiParam(value = "item name") String itemname,
@ApiParam(value = "valid item state (e.g. ON, OFF)", required = true) String value) { @ApiParam(value = "valid item state (e.g. ON, OFF)", required = true) String value) {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
@ -370,8 +316,7 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found"), @ApiResponse(code = 404, message = "Item not found"),
@ApiResponse(code = 400, message = "Item command null") }) @ApiResponse(code = 400, message = "Item command null") })
public Response postItemCommand( public Response postItemCommand(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname,
@ApiParam(value = "valid item command (e.g. ON, OFF, UP, DOWN, REFRESH)", required = true) String value) { @ApiParam(value = "valid item command (e.g. ON, OFF, UP, DOWN, REFRESH)", required = true) String value) {
Item item = getItem(itemname); Item item = getItem(itemname);
Command command = null; Command command = null;
@ -412,8 +357,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @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 = 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.") }) @ApiResponse(code = 405, message = "Member item is not editable.") })
public Response addMember(@PathParam("itemName") @ApiParam(value = "item name", required = true) String itemName, public Response addMember(@PathParam("itemName") @ApiParam(value = "item name") String itemName,
@PathParam("memberItemName") @ApiParam(value = "member item name", required = true) String memberItemName) { @PathParam("memberItemName") @ApiParam(value = "member item name") String memberItemName) {
try { try {
Item item = itemRegistry.getItem(itemName); Item item = itemRegistry.getItem(itemName);
@ -450,8 +395,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @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 = 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.") }) @ApiResponse(code = 405, message = "Member item is not editable.") })
public Response removeMember(@PathParam("itemName") @ApiParam(value = "item name", required = true) String itemName, public Response removeMember(@PathParam("itemName") @ApiParam(value = "item name") String itemName,
@PathParam("memberItemName") @ApiParam(value = "member item name", required = true) String memberItemName) { @PathParam("memberItemName") @ApiParam(value = "member item name") String memberItemName) {
try { try {
Item item = itemRegistry.getItem(itemName); Item item = itemRegistry.getItem(itemName);
@ -487,7 +432,7 @@ public class ItemResource implements RESTResource {
@ApiOperation(value = "Removes an item from the registry.") @ApiOperation(value = "Removes an item from the registry.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found or item is not editable.") }) @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) { if (managedItemProvider.remove(itemname) == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} }
@ -501,8 +446,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found."), @ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Item not editable.") }) @ApiResponse(code = 405, message = "Item not editable.") })
public Response addTag(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname, public Response addTag(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("tag") @ApiParam(value = "tag", required = true) String tag) { @PathParam("tag") @ApiParam(value = "tag") String tag) {
Item item = getItem(itemname); Item item = getItem(itemname);
if (item == null) { if (item == null) {
@ -526,8 +471,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found."), @ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Item not editable.") }) @ApiResponse(code = 405, message = "Item not editable.") })
public Response removeTag(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname, public Response removeTag(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("tag") @ApiParam(value = "tag", required = true) String tag) { @PathParam("tag") @ApiParam(value = "tag") String tag) {
Item item = getItem(itemname); Item item = getItem(itemname);
if (item == null) { if (item == null) {
@ -555,8 +500,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 400, message = "Metadata value empty."), // @ApiResponse(code = 400, message = "Metadata value empty."), //
@ApiResponse(code = 404, message = "Item not found."), // @ApiResponse(code = 404, message = "Item not found."), //
@ApiResponse(code = 405, message = "Metadata not editable.") }) @ApiResponse(code = 405, message = "Metadata not editable.") })
public Response addMetadata(@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname, public Response addMetadata(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("namespace") @ApiParam(value = "namespace", required = true) String namespace, @PathParam("namespace") @ApiParam(value = "namespace") String namespace,
@ApiParam(value = "metadata", required = true) MetadataDTO metadata) { @ApiParam(value = "metadata", required = true) MetadataDTO metadata) {
Item item = getItem(itemname); Item item = getItem(itemname);
@ -587,9 +532,8 @@ public class ItemResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Item not found."), @ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Meta data not editable.") }) @ApiResponse(code = 405, message = "Meta data not editable.") })
public Response removeMetadata( public Response removeMetadata(@PathParam("itemname") @ApiParam(value = "item name") String itemname,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname, @PathParam("namespace") @ApiParam(value = "namespace") String namespace) {
@PathParam("namespace") @ApiParam(value = "namespace", required = true) String namespace) {
Item item = getItem(itemname); Item item = getItem(itemname);
if (item == null) { if (item == null) {
@ -625,8 +569,8 @@ public class ItemResource implements RESTResource {
@ApiResponse(code = 404, message = "Item not found."), @ApiResponse(code = 404, message = "Item not found."),
@ApiResponse(code = 405, message = "Item not editable.") }) @ApiResponse(code = 405, message = "Item not editable.") })
public Response createOrUpdateItem(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders, public Response createOrUpdateItem(final @Context UriInfo uriInfo, final @Context HttpHeaders httpHeaders,
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@PathParam("itemname") @ApiParam(value = "item name", required = true) String itemname, @PathParam("itemname") @ApiParam(value = "item name") String itemname,
@ApiParam(value = "item data", required = true) @Nullable GroupItemDTO item) { @ApiParam(value = "item data", required = true) @Nullable GroupItemDTO item) {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
@ -826,11 +770,4 @@ public class ItemResource implements RESTResource {
private boolean isEditable(String itemName) { private boolean isEditable(String itemName) {
return managedItemProvider.get(itemName) != null; 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.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; 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.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role; import org.openhab.core.auth.Role;
import org.openhab.core.config.core.Configuration; 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.ItemChannelLink;
import org.openhab.core.thing.link.ItemChannelLinkRegistry; import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.openhab.core.thing.link.dto.ItemChannelLinkDTO; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -76,15 +74,18 @@ import io.swagger.annotations.ApiResponses;
@Path(ItemChannelLinkResource.PATH_LINKS) @Path(ItemChannelLinkResource.PATH_LINKS)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(ItemChannelLinkResource.PATH_LINKS) @Api(ItemChannelLinkResource.PATH_LINKS)
@NonNullByDefault
public class ItemChannelLinkResource implements RESTResource { public class ItemChannelLinkResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_LINKS = "links"; public static final String PATH_LINKS = "links";
private ItemChannelLinkRegistry itemChannelLinkRegistry; private final ItemChannelLinkRegistry itemChannelLinkRegistry;
@Context @Activate
UriInfo uriInfo; public ItemChannelLinkResource(final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
}
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -92,8 +93,8 @@ public class ItemChannelLinkResource implements RESTResource {
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ItemChannelLinkDTO.class, responseContainer = "Collection") }) @ApiResponse(code = 200, message = "OK", response = ItemChannelLinkDTO.class, responseContainer = "Collection") })
public Response getAll( public Response getAll(
@QueryParam("channelUID") @ApiParam(value = "filter by channel UID", required = false) @Nullable String channelUID, @QueryParam("channelUID") @ApiParam(value = "filter by channel UID") @Nullable String channelUID,
@QueryParam("itemName") @ApiParam(value = "filter by item name", required = false) @Nullable String itemName) { @QueryParam("itemName") @ApiParam(value = "filter by item name") @Nullable String itemName) {
Stream<ItemChannelLinkDTO> linkStream = itemChannelLinkRegistry.getAll().stream().map(this::toBeans); Stream<ItemChannelLinkDTO> linkStream = itemChannelLinkRegistry.getAll().stream().map(this::toBeans);
if (channelUID != null) { if (channelUID != null) {
@ -134,7 +135,7 @@ public class ItemChannelLinkResource implements RESTResource {
@ApiResponse(code = 405, message = "Link is not editable") }) @ApiResponse(code = 405, message = "Link is not editable") })
public Response link(@PathParam("itemName") @ApiParam(value = "itemName") String itemName, public Response link(@PathParam("itemName") @ApiParam(value = "itemName") String itemName,
@PathParam("channelUID") @ApiParam(value = "channelUID") String channelUid, @PathParam("channelUID") @ApiParam(value = "channelUID") String channelUid,
@ApiParam(value = "link data", required = false) ItemChannelLinkDTO bean) { @ApiParam(value = "link data") @Nullable ItemChannelLinkDTO bean) {
ItemChannelLink link; ItemChannelLink link;
if (bean == null) { if (bean == null) {
link = new ItemChannelLink(itemName, new ChannelUID(channelUid), new Configuration()); 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) { private ItemChannelLinkDTO toBeans(ItemChannelLink link) {
return new ItemChannelLinkDTO(link.getItemName(), link.getLinkedUID().toString(), return new ItemChannelLinkDTO(link.getItemName(), link.getLinkedUID().toString(),
link.getConfiguration().getProperties()); 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;
import javax.ws.rs.core.Response.Status; 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.auth.Role;
import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.rest.JSONResponse; 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.persistence.dto.PersistenceServiceDTO;
import org.openhab.core.types.State; import org.openhab.core.types.State;
import org.openhab.core.types.TypeParser; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -94,57 +95,33 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired @JSONRequired
@Path(PersistenceResource.PATH_PERSISTENCE) @Path(PersistenceResource.PATH_PERSISTENCE)
@Api(PersistenceResource.PATH_PERSISTENCE) @Api(PersistenceResource.PATH_PERSISTENCE)
@NonNullByDefault
public class PersistenceResource implements RESTResource { 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 final Logger logger = LoggerFactory.getLogger(PersistenceResource.class);
private static final String MODIFYABLE = "Modifiable"; private static final String MODIFYABLE = "Modifiable";
private static final String QUERYABLE = "Queryable"; private static final String QUERYABLE = "Queryable";
private static final String STANDARD = "Standard"; private static final String STANDARD = "Standard";
// The URI path to this resource private final ItemRegistry itemRegistry;
public static final String PATH_PERSISTENCE = "persistence"; private final LocaleService localeService;
private final PersistenceServiceRegistry persistenceServiceRegistry;
private final TimeZoneProvider timeZoneProvider;
private ItemRegistry itemRegistry; @Activate
private PersistenceServiceRegistry persistenceServiceRegistry; public PersistenceResource( //
private TimeZoneProvider timeZoneProvider; final @Reference ItemRegistry itemRegistry, //
final @Reference LocaleService localeService,
private LocaleService localeService; final @Reference PersistenceServiceRegistry persistenceServiceRegistry,
final @Reference TimeZoneProvider timeZoneProvider) {
@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) {
this.itemRegistry = itemRegistry; 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; this.localeService = localeService;
} this.persistenceServiceRegistry = persistenceServiceRegistry;
this.timeZoneProvider = timeZoneProvider;
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
} }
@GET @GET
@ -153,7 +130,7 @@ public class PersistenceResource implements RESTResource {
@ApiOperation(value = "Gets a list of persistence services.", response = String.class, responseContainer = "List") @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")) @ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = String.class, responseContainer = "List"))
public Response httpGetPersistenceServices(@Context HttpHeaders headers, 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); Locale locale = localeService.getLocale(language);
Object responseObject = getPersistenceServiceList(locale); 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") @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")) @ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = String.class, responseContainer = "List"))
public Response httpGetPersistenceServiceItems(@Context HttpHeaders headers, 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); return getServiceItemList(serviceId);
} }
@ -179,17 +156,16 @@ public class PersistenceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ItemHistoryDTO.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ItemHistoryDTO.class),
@ApiResponse(code = 404, message = "Unknown Item or persistence service") }) @ApiResponse(code = 404, message = "Unknown Item or persistence service") })
public Response httpGetPersistenceItemData(@Context HttpHeaders headers, 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 = "Id of the persistence service. If not provided the default service will be used") @QueryParam("serviceId") @Nullable 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. Will default to 1 day before endtime. [" @ApiParam(value = "Start time of the data to return. Will default to 1 day before endtime. ["
+ DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS + 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. [" @ApiParam(value = "End time of the data to return. Will default to current time. ["
+ DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS + DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS + "]") @QueryParam("endtime") @Nullable String endTime,
+ "]", required = false) @QueryParam("endtime") String endTime, @ApiParam(value = "Page number of data to return. This parameter will enable paging.") @QueryParam("page") int pageNumber,
@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.") @QueryParam("pagelength") int pageLength,
@ApiParam(value = "The length of each page.", required = false) @QueryParam("pagelength") int pageLength, @ApiParam(value = "Gets one value before and after the requested period.") @QueryParam("boundary") boolean boundary) {
@ApiParam(value = "Gets one value before and after the requested period.", required = false) @QueryParam("boundary") boolean boundary) {
return getItemHistoryDTO(serviceId, itemName, startTime, endTime, pageNumber, pageLength, 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") }) @ApiResponse(code = 404, message = "Unknown persistence service") })
public Response httpDeletePersistenceServiceItem(@Context HttpHeaders headers, public Response httpDeletePersistenceServiceItem(@Context HttpHeaders headers,
@ApiParam(value = "Id of the persistence service.", required = true) @QueryParam("serviceId") String serviceId, @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 @ApiParam(value = "Start time of the data to return. [" + DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS
+ "]", required = true) @QueryParam("starttime") String startTime, + "]", required = true) @QueryParam("starttime") String startTime,
@ApiParam(value = "End time of the data to return. [" + DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS @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), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ItemHistoryDTO.class),
@ApiResponse(code = 404, message = "Unknown Item or persistence service") }) @ApiResponse(code = 404, message = "Unknown Item or persistence service") })
public Response httpPutPersistenceItemData(@Context HttpHeaders headers, 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 = "Id of the persistence service. If not provided the default service will be used") @QueryParam("serviceId") @Nullable String serviceId,
@ApiParam(value = "The item name.", required = true) @PathParam("itemname") String itemName, @ApiParam(value = "The item name.") @PathParam("itemname") String itemName,
@ApiParam(value = "Time of the data to be stored. Will default to current time. [" @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, + 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) { @ApiParam(value = "The state to store.", required = true) @QueryParam("state") String value) {
@ -233,22 +209,26 @@ public class PersistenceResource implements RESTResource {
return dateTime.getZonedDateTime(); return dateTime.getZonedDateTime();
} }
private Response getItemHistoryDTO(String serviceId, String itemName, String timeBegin, String timeEnd, private Response getItemHistoryDTO(@Nullable String serviceId, String itemName, @Nullable String timeBegin,
int pageNumber, int pageLength, boolean boundary) { @Nullable String timeEnd, int pageNumber, int pageLength, boolean boundary) {
// Benchmarking timer... // Benchmarking timer...
long timerStart = System.currentTimeMillis(); long timerStart = System.currentTimeMillis();
@Nullable
ItemHistoryDTO dto = createDTO(serviceId, itemName, timeBegin, timeEnd, pageNumber, pageLength, boundary); ItemHistoryDTO dto = createDTO(serviceId, itemName, timeBegin, timeEnd, pageNumber, pageLength, boundary);
if (dto == null) { 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); logger.debug("Persistence returned {} rows in {}ms", dto.datapoints, System.currentTimeMillis() - timerStart);
return JSONResponse.createResponse(Status.OK, dto, ""); return JSONResponse.createResponse(Status.OK, dto, "");
} }
protected ItemHistoryDTO createDTO(String serviceId, String itemName, String timeBegin, String timeEnd, protected @Nullable ItemHistoryDTO createDTO(@Nullable String serviceId, String itemName,
int pageNumber, int pageLength, boolean boundary) { @Nullable String timeBegin, @Nullable String timeEnd, int pageNumber, int pageLength, boolean boundary) {
// If serviceId is null, then use the default service // If serviceId is null, then use the default service
PersistenceService service = null; PersistenceService service = null;
String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId(); String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId();
@ -315,7 +295,7 @@ public class PersistenceResource implements RESTResource {
filter.setPageSize(1); filter.setPageSize(1);
filter.setOrdering(Ordering.DESCENDING); filter.setOrdering(Ordering.DESCENDING);
result = qService.query(filter); result = qService.query(filter);
if (result != null && result.iterator().hasNext()) { if (result.iterator().hasNext()) {
dto.addData(dateTimeBegin.toInstant().toEpochMilli(), result.iterator().next().getState()); dto.addData(dateTimeBegin.toInstant().toEpochMilli(), result.iterator().next().getState());
quantity++; quantity++;
} }
@ -334,7 +314,6 @@ public class PersistenceResource implements RESTResource {
filter.setOrdering(Ordering.ASCENDING); filter.setOrdering(Ordering.ASCENDING);
result = qService.query(filter); result = qService.query(filter);
if (result != null) {
Iterator<HistoricItem> it = result.iterator(); Iterator<HistoricItem> it = result.iterator();
// Iterate through the data // Iterate through the data
@ -356,7 +335,6 @@ public class PersistenceResource implements RESTResource {
quantity++; quantity++;
lastItem = historicItem; lastItem = historicItem;
} }
}
if (boundary) { if (boundary) {
// Get the value after the end time. // Get the value after the end time.
@ -364,7 +342,7 @@ public class PersistenceResource implements RESTResource {
filter.setPageSize(1); filter.setPageSize(1);
filter.setOrdering(Ordering.ASCENDING); filter.setOrdering(Ordering.ASCENDING);
result = qService.query(filter); result = qService.query(filter);
if (result != null && result.iterator().hasNext()) { if (result.iterator().hasNext()) {
dto.addData(dateTimeEnd.toInstant().toEpochMilli(), result.iterator().next().getState()); dto.addData(dateTimeEnd.toInstant().toEpochMilli(), result.iterator().next().getState());
quantity++; quantity++;
} }
@ -401,7 +379,7 @@ public class PersistenceResource implements RESTResource {
return dtoList; return dtoList;
} }
private Response getServiceItemList(String serviceId) { private Response getServiceItemList(@Nullable String serviceId) {
// If serviceId is null, then use the default service // If serviceId is null, then use the default service
PersistenceService service = null; PersistenceService service = null;
if (serviceId == null) { if (serviceId == null) {
@ -426,7 +404,8 @@ public class PersistenceResource implements RESTResource {
return JSONResponse.createResponse(Status.OK, qService.getItemInfo(), ""); 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 // For deleting, we must specify a service id - don't use the default service
if (serviceId == null || serviceId.length() == 0) { if (serviceId == null || serviceId.length() == 0) {
logger.debug("Persistence service must be specified for delete operations."); logger.debug("Persistence service must be specified for delete operations.");
@ -448,7 +427,7 @@ public class PersistenceResource implements RESTResource {
ModifiablePersistenceService mService = (ModifiablePersistenceService) service; 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"); 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(); 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 // If serviceId is null, then use the default service
PersistenceService service = null;
String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId(); String effectiveServiceId = serviceId != null ? serviceId : persistenceServiceRegistry.getDefaultId();
service = persistenceServiceRegistry.get(effectiveServiceId); PersistenceService service = persistenceServiceRegistry.get(effectiveServiceId);
if (service == null) { if (service == null) {
logger.warn("Persistence service not found '{}'.", effectiveServiceId); logger.warn("Persistence service not found '{}'.", effectiveServiceId);
@ -490,10 +468,6 @@ public class PersistenceResource implements RESTResource {
Item item; Item item;
try { try {
if (itemRegistry == null) {
logger.warn("Item registry not set.");
return JSONResponse.createErrorResponse(Status.CONFLICT, "Item registry not set.");
}
item = itemRegistry.getItem(itemName); item = itemRegistry.getItem(itemName);
} catch (ItemNotFoundException e) { } catch (ItemNotFoundException e) {
logger.warn("Item not found '{}'.", itemName); logger.warn("Item not found '{}'.", itemName);
@ -528,10 +502,4 @@ public class PersistenceResource implements RESTResource {
mService.store(item, Date.from(dateTime.toInstant()), state); mService.store(item, Date.from(dateTime.toInstant()), state);
return Response.status(Status.OK).build(); 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.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role; import org.openhab.core.auth.Role;
import org.openhab.core.io.rest.LocaleService; 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.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry; import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ChannelTypeUID; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource; 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.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -75,16 +73,25 @@ import io.swagger.annotations.ApiResponses;
@Path(ProfileTypeResource.PATH_PROFILE_TYPES) @Path(ProfileTypeResource.PATH_PROFILE_TYPES)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(ProfileTypeResource.PATH_PROFILE_TYPES) @Api(ProfileTypeResource.PATH_PROFILE_TYPES)
@NonNullByDefault
public class ProfileTypeResource implements RESTResource { public class ProfileTypeResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_PROFILE_TYPES = "profile-types"; 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; @Activate
private ChannelTypeRegistry channelTypeRegistry; public ProfileTypeResource( //
private LocaleService localeService; final @Reference ChannelTypeRegistry channelTypeRegistry, //
final @Reference LocaleService localeService, //
final @Reference ProfileTypeRegistry profileTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
this.localeService = localeService;
this.profileTypeRegistry = profileTypeRegistry;
}
@GET @GET
@RolesAllowed({ Role.USER }) @RolesAllowed({ Role.USER })
@ -92,19 +99,20 @@ public class ProfileTypeResource implements RESTResource {
@ApiOperation(value = "Gets all available profile types.", response = ProfileTypeDTO.class, responseContainer = "Set") @ApiOperation(value = "Gets all available profile types.", response = ProfileTypeDTO.class, responseContainer = "Set")
@ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ProfileTypeDTO.class, responseContainer = "Set")) @ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = ProfileTypeDTO.class, responseContainer = "Set"))
public Response getAll( public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("channelTypeUID") @ApiParam(value = "channel type filter", required = false) @Nullable String channelTypeUID, @QueryParam("channelTypeUID") @ApiParam(value = "channel type filter") @Nullable String channelTypeUID,
@QueryParam("itemType") @ApiParam(value = "item type filter", required = false) @Nullable String itemType) { @QueryParam("itemType") @ApiParam(value = "item type filter") @Nullable String itemType) {
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
return Response.ok(new Stream2JSONInputStream(getProfileTypes(locale, channelTypeUID, itemType))).build(); 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)) 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) { if (channelTypeUID == null) {
return t -> true; return t -> true;
} }
@ -122,7 +130,7 @@ public class ProfileTypeResource implements RESTResource {
return t -> false; return t -> false;
} }
private Predicate<ProfileType> matchesItemType(String itemType) { private Predicate<ProfileType> matchesItemType(@Nullable String itemType) {
if (itemType == null) { if (itemType == null) {
return t -> true; return t -> true;
} }
@ -171,47 +179,4 @@ public class ProfileTypeResource implements RESTResource {
} }
return false; 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;
import javax.ws.rs.core.Response.Status; 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.auth.Role;
import org.openhab.core.config.core.ConfigConstants; import org.openhab.core.config.core.ConfigConstants;
import org.openhab.core.config.core.ConfigDescription; 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.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -87,6 +87,7 @@ import io.swagger.annotations.ApiResponses;
@Path(ConfigurableServiceResource.PATH_SERVICES) @Path(ConfigurableServiceResource.PATH_SERVICES)
@RolesAllowed({ Role.ADMIN }) @RolesAllowed({ Role.ADMIN })
@Api(ConfigurableServiceResource.PATH_SERVICES) @Api(ConfigurableServiceResource.PATH_SERVICES)
@NonNullByDefault
public class ConfigurableServiceResource implements RESTResource { public class ConfigurableServiceResource implements RESTResource {
/** The URI path to this resource */ /** 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 Logger logger = LoggerFactory.getLogger(ConfigurableServiceResource.class);
private final BundleContext bundleContext; private final BundleContext bundleContext;
private final ConfigDescriptionRegistry configDescRegistry;
private ConfigurationService configurationService; private final ConfigurationService configurationService;
private ConfigDescriptionRegistry configDescRegistry;
@Activate @Activate
public ConfigurableServiceResource(final BundleContext bundleContext) { public ConfigurableServiceResource( //
final BundleContext bundleContext, //
final @Reference ConfigurationService configurationService,
final @Reference ConfigDescriptionRegistry configDescRegistry) {
this.bundleContext = bundleContext; this.bundleContext = bundleContext;
this.configDescRegistry = configDescRegistry;
this.configurationService = configurationService;
} }
@GET @GET
@ -129,7 +134,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiOperation(value = "Get configurable service for given service ID.") @ApiOperation(value = "Get configurable service for given service ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ConfigurableServiceDTO.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ConfigurableServiceDTO.class),
@ApiResponse(code = 404, message = "Not found") }) @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); ConfigurableServiceDTO configurableService = getServiceById(serviceId);
if (configurableService != null) { if (configurableService != null) {
return Response.ok(configurableService).build(); 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); ConfigurableServiceDTO multiService = getMultiConfigServiceById(serviceId);
if (multiService != null) { if (multiService != null) {
return multiService; return multiService;
@ -153,7 +158,7 @@ public class ConfigurableServiceResource implements RESTResource {
return null; return null;
} }
private ConfigurableServiceDTO getMultiConfigServiceById(String serviceId) { private @Nullable ConfigurableServiceDTO getMultiConfigServiceById(String serviceId) {
String filter = "(&(" + Constants.SERVICE_PID + "=" + serviceId + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID String filter = "(&(" + Constants.SERVICE_PID + "=" + serviceId + ")(" + ConfigurationAdmin.SERVICE_FACTORYPID
+ "=*))"; + "=*))";
List<ConfigurableServiceDTO> services = getServicesByFilter(filter); List<ConfigurableServiceDTO> services = getServicesByFilter(filter);
@ -170,7 +175,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = ConfigurableServiceDTO.class, responseContainer = "List") }) @ApiResponse(code = 200, message = "OK", response = ConfigurableServiceDTO.class, responseContainer = "List") })
public List<ConfigurableServiceDTO> getMultiConfigServicesByFactoryPid( 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); List<ConfigurableServiceDTO> services = collectServicesById(serviceId);
return services; return services;
} }
@ -186,8 +191,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiOperation(value = "Get service configuration for given service ID.") @ApiOperation(value = "Get service configuration for given service ID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 500, message = "Configuration can not be read due to internal error") }) @ApiResponse(code = 500, message = "Configuration can not be read due to internal error") })
public Response getConfiguration( public Response getConfiguration(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId) {
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId) {
try { try {
Configuration configuration = configurationService.get(serviceId); Configuration configuration = configurationService.get(serviceId);
return configuration != null ? Response.ok(configuration.getProperties()).build() 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), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 204, message = "No old configuration"), @ApiResponse(code = 204, message = "No old configuration"),
@ApiResponse(code = 500, message = "Configuration can not be updated due to internal error") }) @ApiResponse(code = 500, message = "Configuration can not be updated due to internal error") })
public Response updateConfiguration( public Response updateConfiguration(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId,
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId, @Nullable Map<String, Object> configuration) {
Map<String, Object> configuration) {
try { try {
Configuration oldConfiguration = configurationService.get(serviceId); Configuration oldConfiguration = configurationService.get(serviceId);
configurationService.update(serviceId, new Configuration(normalizeConfiguration(configuration, 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()) { if (properties == null || properties.isEmpty()) {
return properties; return properties;
} }
@ -253,8 +257,7 @@ public class ConfigurableServiceResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 204, message = "No old configuration"), @ApiResponse(code = 204, message = "No old configuration"),
@ApiResponse(code = 500, message = "Configuration can not be deleted due to internal error") }) @ApiResponse(code = 500, message = "Configuration can not be deleted due to internal error") })
public Response deleteConfiguration( public Response deleteConfiguration(@PathParam("serviceId") @ApiParam(value = "service ID") String serviceId) {
@PathParam("serviceId") @ApiParam(value = "service ID", required = true) String serviceId) {
try { try {
Configuration oldConfiguration = configurationService.get(serviceId); Configuration oldConfiguration = configurationService.get(serviceId);
configurationService.delete(serviceId); configurationService.delete(serviceId);
@ -300,7 +303,7 @@ public class ConfigurableServiceResource implements RESTResource {
return services; return services;
} }
private String getConfigDescriptionByFactoryPid(String factoryPid) { private @Nullable String getConfigDescriptionByFactoryPid(String factoryPid) {
String configDescriptionURI = null; String configDescriptionURI = null;
String filter = "(" + Constants.SERVICE_PID + "=" + factoryPid + ")"; String filter = "(" + Constants.SERVICE_PID + "=" + factoryPid + ")";
@ -379,27 +382,4 @@ public class ConfigurableServiceResource implements RESTResource {
return first; 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.Response.Status;
import javax.ws.rs.core.UriInfo; 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.auth.Role;
import org.openhab.core.config.core.ConfigDescription; import org.openhab.core.config.core.ConfigDescription;
import org.openhab.core.config.core.ConfigDescriptionRegistry; 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.ThingType;
import org.openhab.core.thing.type.ThingTypeRegistry; import org.openhab.core.thing.type.ThingTypeRegistry;
import org.openhab.core.thing.util.ThingHelper; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -136,6 +137,7 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired @JSONRequired
@Path(ThingResource.PATH_THINGS) @Path(ThingResource.PATH_THINGS)
@Api(ThingResource.PATH_THINGS) @Api(ThingResource.PATH_THINGS)
@NonNullByDefault
public class ThingResource implements RESTResource { public class ThingResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(ThingResource.class); private final Logger logger = LoggerFactory.getLogger(ThingResource.class);
@ -143,34 +145,59 @@ public class ThingResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_THINGS = "things"; public static final String PATH_THINGS = "things";
private ItemChannelLinkRegistry itemChannelLinkRegistry; private final ChannelTypeRegistry channelTypeRegistry;
private ItemFactory itemFactory; private final ConfigStatusService configStatusService;
private ItemRegistry itemRegistry; private final ConfigDescriptionRegistry configDescRegistry;
private ManagedItemChannelLinkProvider managedItemChannelLinkProvider; private final FirmwareRegistry firmwareRegistry;
private ManagedItemProvider managedItemProvider; private final FirmwareUpdateService firmwareUpdateService;
private ManagedThingProvider managedThingProvider; private final ItemChannelLinkRegistry itemChannelLinkRegistry;
private ThingRegistry thingRegistry; private final ItemFactory itemFactory;
private ConfigStatusService configStatusService; private final ItemRegistry itemRegistry;
private ConfigDescriptionRegistry configDescRegistry; private final LocaleService localeService;
private ThingTypeRegistry thingTypeRegistry; private final ManagedItemChannelLinkProvider managedItemChannelLinkProvider;
private ChannelTypeRegistry channelTypeRegistry; private final ManagedItemProvider managedItemProvider;
private ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService; private final ManagedThingProvider managedThingProvider;
private FirmwareUpdateService firmwareUpdateService; private final ThingManager thingManager;
private FirmwareRegistry firmwareRegistry; private final ThingRegistry thingRegistry;
private ThingManager thingManager; private final ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService;
private final ThingTypeRegistry thingTypeRegistry;
private LocaleService localeService; private @Context @NonNullByDefault({}) UriInfo uriInfo;
@Context @Activate
private UriInfo uriInfo; public ThingResource( //
final @Reference ChannelTypeRegistry channelTypeRegistry,
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference ConfigStatusService configStatusService,
protected void setLocaleService(LocaleService localeService) { 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; this.localeService = localeService;
} this.managedItemChannelLinkProvider = managedItemChannelLinkProvider;
this.managedItemProvider = managedItemProvider;
protected void unsetLocaleService(LocaleService localeService) { this.managedThingProvider = managedThingProvider;
this.localeService = null; 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), @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 = 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.") }) @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) { @ApiParam(value = "thing data", required = true) ThingDTO thingBean) {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
@ -212,7 +240,9 @@ public class ThingResource implements RESTResource {
// turn the ThingDTO's configuration into a Configuration // turn the ThingDTO's configuration into a Configuration
Configuration configuration = new Configuration( Configuration configuration = new Configuration(
normalizeConfiguration(thingBean.configuration, thingTypeUID, thingUID)); normalizeConfiguration(thingBean.configuration, thingTypeUID, thingUID));
if (thingUID != null) {
normalizeChannels(thingBean, thingUID); normalizeChannels(thingBean, thingUID);
}
Thing thing = thingRegistry.createThingOfType(thingTypeUID, thingUID, bridgeUID, thingBean.label, Thing thing = thingRegistry.createThingOfType(thingTypeUID, thingUID, bridgeUID, thingBean.label,
configuration); configuration);
@ -254,7 +284,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Get all available things.", response = EnrichedThingDTO.class, responseContainer = "Set") @ApiOperation(value = "Get all available things.", response = EnrichedThingDTO.class, responseContainer = "Set")
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = EnrichedThingDTO.class, responseContainer = "Set") }) @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); final Locale locale = localeService.getLocale(language);
Stream<EnrichedThingDTO> thingStream = thingRegistry.stream().map(t -> convertToEnrichedThingDTO(t, locale)) 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.") @ApiOperation(value = "Gets thing by UID.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ThingDTO.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ThingDTO.class),
@ApiResponse(code = 404, message = "Thing not found.") }) @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) { @PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID) {
final Locale locale = localeService.getLocale(language); 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 = 202, message = "ACCEPTED for asynchronous deletion."),
@ApiResponse(code = 404, message = "Thing not found."), @ApiResponse(code = 404, message = "Thing not found."),
@ApiResponse(code = 409, message = "Thing could not be deleted because it's not editable.") }) @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, @PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@DefaultValue("false") @QueryParam("force") @ApiParam(value = "force") boolean force) { @DefaultValue("false") @QueryParam("force") @ApiParam(value = "force") boolean force) {
final Locale locale = localeService.getLocale(language); 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 // ask whether the Thing exists as a managed thing, so it can get
// updated, 409 otherwise // updated, 409 otherwise
Thing managed = managedThingProvider.get(thingUIDObject); Thing managed = managedThingProvider.get(thingUIDObject);
if (null == managed) { if (managed == null) {
logger.info("Received HTTP DELETE request for update at '{}' for an unmanaged thing '{}'.", logger.info("Received HTTP DELETE request for update at '{}' for an unmanaged thing '{}'.",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
return getThingResponse(Status.CONFLICT, thing, locale, 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 // only move on if Thing is known to be managed, so it can get updated
if (force) { if (force) {
if (null == thingRegistry.forceRemove(thingUIDObject)) { if (thingRegistry.forceRemove(thingUIDObject) == null) {
return getThingResponse(Status.INTERNAL_SERVER_ERROR, thing, locale, return getThingResponse(Status.INTERNAL_SERVER_ERROR, thing, locale,
"Cannot delete Thing " + thingUID + " for unknown reasons."); "Cannot delete Thing " + thingUID + " for unknown reasons.");
} }
} else { } else {
if (null != thingRegistry.remove(thingUIDObject)) { if (thingRegistry.remove(thingUIDObject) != null) {
return getThingResponse(Status.ACCEPTED, thing, locale, 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), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ThingDTO.class),
@ApiResponse(code = 404, message = "Thing not found."), @ApiResponse(code = 404, message = "Thing not found."),
@ApiResponse(code = 409, message = "Thing could not be updated as it is not editable.") }) @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, @PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID,
@ApiParam(value = "thing", required = true) ThingDTO thingBean) throws IOException { @ApiParam(value = "thing", required = true) ThingDTO thingBean) throws IOException {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
@ -365,7 +399,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists at all, 404 otherwise // ask whether the Thing exists at all, 404 otherwise
Thing thing = thingRegistry.get(thingUIDObject); 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(), logger.info("Received HTTP PUT request for update at '{}' for the unknown thing '{}'.", uriInfo.getPath(),
thingUID); thingUID);
return getThingNotFoundResponse(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 // ask whether the Thing exists as a managed thing, so it can get
// updated, 409 otherwise // updated, 409 otherwise
Thing managed = managedThingProvider.get(thingUIDObject); 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(), logger.info("Received HTTP PUT request for update at '{}' for an unmanaged thing '{}'.", uriInfo.getPath(),
thingUID); thingUID);
return getThingResponse(Status.CONFLICT, thing, locale, return getThingResponse(Status.CONFLICT, thing, locale,
@ -390,7 +424,7 @@ public class ThingResource implements RESTResource {
// update, returns null in case Thing cannot be found // update, returns null in case Thing cannot be found
Thing oldthing = managedThingProvider.update(thing); Thing oldthing = managedThingProvider.update(thing);
if (null == oldthing) { if (oldthing == null) {
return getThingNotFoundResponse(thingUID); 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 = 400, message = "Configuration of the thing is not valid."),
@ApiResponse(code = 404, message = "Thing not found"), @ApiResponse(code = 404, message = "Thing not found"),
@ApiResponse(code = 409, message = "Thing could not be updated as it is not editable.") }) @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, @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 { throws IOException {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
@ -425,7 +460,7 @@ public class ThingResource implements RESTResource {
// ask whether the Thing exists at all, 404 otherwise // ask whether the Thing exists at all, 404 otherwise
Thing thing = thingRegistry.get(thingUIDObject); 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 '{}'.", logger.info("Received HTTP PUT request for update configuration at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(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 // ask whether the Thing exists as a managed thing, so it can get
// updated, 409 otherwise // updated, 409 otherwise
Thing managed = managedThingProvider.get(thingUIDObject); 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 '{}'.", logger.info("Received HTTP PUT request for update configuration at '{}' for an unmanaged thing '{}'.",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
return getThingResponse(Status.CONFLICT, thing, locale, return getThingResponse(Status.CONFLICT, thing, locale,
@ -468,13 +503,14 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing's status.") @ApiOperation(value = "Gets thing's status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Thing not found.") }) @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 { @PathParam("thingUID") @ApiParam(value = "thing") String thingUID) throws IOException {
ThingUID thingUIDObject = new ThingUID(thingUID); ThingUID thingUIDObject = new ThingUID(thingUID);
// Check if the Thing exists, 404 if not // Check if the Thing exists, 404 if not
Thing thing = thingRegistry.get(thingUIDObject); 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 '{}'.", logger.info("Received HTTP GET request for thing config status at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID); return getThingNotFoundResponse(thingUID);
@ -491,7 +527,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Sets the thing enabled status.") @ApiOperation(value = "Sets the thing enabled status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Thing not found.") }) @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, @PathParam("thingUID") @ApiParam(value = "thing") String thingUID,
@ApiParam(value = "enabled") String enabled) throws IOException { @ApiParam(value = "enabled") String enabled) throws IOException {
final Locale locale = localeService.getLocale(language); final Locale locale = localeService.getLocale(language);
@ -500,7 +537,7 @@ public class ThingResource implements RESTResource {
// Check if the Thing exists, 404 if not // Check if the Thing exists, 404 if not
Thing thing = thingRegistry.get(thingUIDObject); 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 '{}'.", logger.info("Received HTTP PUT request for set enabled at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID); return getThingNotFoundResponse(thingUID);
@ -519,13 +556,14 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing's config status.") @ApiOperation(value = "Gets thing's config status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = String.class),
@ApiResponse(code = 404, message = "Thing not found.") }) @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 { @PathParam("thingUID") @ApiParam(value = "thing") String thingUID) throws IOException {
ThingUID thingUIDObject = new ThingUID(thingUID); ThingUID thingUIDObject = new ThingUID(thingUID);
// Check if the Thing exists, 404 if not // Check if the Thing exists, 404 if not
Thing thing = thingRegistry.get(thingUIDObject); 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 '{}'.", logger.info("Received HTTP GET request for thing config status at '{}' for the unknown thing '{}'.",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
return getThingNotFoundResponse(thingUID); return getThingNotFoundResponse(thingUID);
@ -546,7 +584,7 @@ public class ThingResource implements RESTResource {
@ApiResponse(code = 400, message = "Firmware update preconditions not satisfied."), @ApiResponse(code = 400, message = "Firmware update preconditions not satisfied."),
@ApiResponse(code = 404, message = "Thing not found.") }) @ApiResponse(code = 404, message = "Thing not found.") })
public Response updateFirmware( 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("thingUID") @ApiParam(value = "thing") String thingUID,
@PathParam("firmwareVersion") @ApiParam(value = "version") String firmwareVersion) throws IOException { @PathParam("firmwareVersion") @ApiParam(value = "version") String firmwareVersion) throws IOException {
Thing thing = thingRegistry.get(new ThingUID(thingUID)); Thing thing = thingRegistry.get(new ThingUID(thingUID));
@ -556,16 +594,15 @@ public class ThingResource implements RESTResource {
return getThingNotFoundResponse(thingUID); return getThingNotFoundResponse(thingUID);
} }
if (firmwareVersion == null || firmwareVersion.isEmpty()) { if (firmwareVersion.isEmpty()) {
logger.info( logger.info(
"Received HTTP PUT request for firmware update at '{}' for thing '{}' with unknown firmware version '{}'.", "Received HTTP PUT request for firmware update at '{}' for thing '{}' with unknown firmware version '{}'.",
uriInfo.getPath(), thingUID, firmwareVersion); uriInfo.getPath(), thingUID, firmwareVersion);
return JSONResponse.createResponse(Status.BAD_REQUEST, null, "Firmware version is empty"); return JSONResponse.createResponse(Status.BAD_REQUEST, null, "Firmware version is empty");
} }
ThingUID uid = thing.getUID();
try { try {
firmwareUpdateService.updateFirmware(uid, firmwareVersion, localeService.getLocale(language)); firmwareUpdateService.updateFirmware(thing.getUID(), firmwareVersion, localeService.getLocale(language));
} catch (IllegalArgumentException | IllegalStateException ex) { } catch (IllegalArgumentException | IllegalStateException ex) {
return JSONResponse.createResponse(Status.BAD_REQUEST, null, return JSONResponse.createResponse(Status.BAD_REQUEST, null,
"Firmware update preconditions not satisfied."); "Firmware update preconditions not satisfied.");
@ -579,7 +616,8 @@ public class ThingResource implements RESTResource {
@ApiOperation(value = "Gets thing's firmware status.") @ApiOperation(value = "Gets thing's firmware status.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 204, message = "No firmware status provided by this Thing.") }) @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 { @PathParam("thingUID") @ApiParam(value = "thing") String thingUID) throws IOException {
ThingUID thingUIDObject = new ThingUID(thingUID); ThingUID thingUIDObject = new ThingUID(thingUID);
FirmwareStatusDTO firmwareStatusDto = getThingFirmwareStatusInfo(thingUIDObject); FirmwareStatusDTO firmwareStatusDto = getThingFirmwareStatusInfo(thingUIDObject);
@ -597,10 +635,10 @@ public class ThingResource implements RESTResource {
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 204, message = "No firmwares found.") }) @ApiResponse(code = 204, message = "No firmwares found.") })
public Response getFirmwares(@PathParam("thingUID") @ApiParam(value = "thingUID") String thingUID, 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); ThingUID aThingUID = new ThingUID(thingUID);
Thing thing = thingRegistry.get(aThingUID); Thing thing = thingRegistry.get(aThingUID);
if (null == thing) { if (thing == null) {
logger.info( logger.info(
"Received HTTP GET request for listing available firmwares at {} for unknown thing with UID '{}'", "Received HTTP GET request for listing available firmwares at {} for unknown thing with UID '{}'",
uriInfo.getPath(), thingUID); uriInfo.getPath(), thingUID);
@ -622,7 +660,7 @@ public class ThingResource implements RESTResource {
firmware.getPrerequisiteVersion(), firmware.getChangelog()); firmware.getPrerequisiteVersion(), firmware.getChangelog());
} }
private FirmwareStatusDTO getThingFirmwareStatusInfo(ThingUID thingUID) { private @Nullable FirmwareStatusDTO getThingFirmwareStatusInfo(ThingUID thingUID) {
FirmwareStatusInfo info = firmwareUpdateService.getFirmwareStatusInfo(thingUID); FirmwareStatusInfo info = firmwareUpdateService.getFirmwareStatusInfo(thingUID);
if (info != null) { if (info != null) {
return buildFirmwareStatusDTO(info); 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 * @param errormessage an optional error message (may be null), ignored if the status family is successful
* @return Response * @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, ThingStatusInfo thingStatusInfo = thingStatusInfoI18nLocalizationService.getLocalizedThingStatusInfo(thing,
locale); locale);
boolean managed = managedThingProvider.get(thing.getUID()) != null; boolean managed = thing != null && managedThingProvider.get(thing.getUID()) != null;
EnrichedThingDTO enrichedThingDTO = thing != null EnrichedThingDTO enrichedThingDTO = thing != null
? EnrichedThingDTOMapper.map(thing, thingStatusInfo, this.getThingFirmwareStatusInfo(thing.getUID()), ? EnrichedThingDTOMapper.map(thing, thingStatusInfo, this.getThingFirmwareStatusInfo(thing.getUID()),
getLinkedItemsMap(thing), managed) getLinkedItemsMap(thing), managed)
@ -666,89 +705,6 @@ public class ThingResource implements RESTResource {
return JSONResponse.createResponse(status, enrichedThingDTO, errormessage); 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) { private EnrichedThingDTO convertToEnrichedThingDTO(Thing thing, Locale locale) {
boolean managed = managedThingProvider.get(thing.getUID()) != null; boolean managed = managedThingProvider.get(thing.getUID()) != null;
ThingStatusInfo thingStatusInfo = thingStatusInfoI18nLocalizationService.getLocalizedThingStatusInfo(thing, ThingStatusInfo thingStatusInfo = thingStatusInfoI18nLocalizationService.getLocalizedThingStatusInfo(thing,
@ -772,62 +728,8 @@ public class ThingResource implements RESTResource {
} }
} }
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) { ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID) {
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) {
if (properties == null || properties.isEmpty()) { if (properties == null || properties.isEmpty()) {
return properties; return properties;
} }
@ -845,7 +747,7 @@ public class ThingResource implements RESTResource {
configDescriptions.add(typeConfigDesc); configDescriptions.add(typeConfigDesc);
} }
} }
if (getConfigDescriptionURI(thingUID) != null) { if (thingUID != null) {
ConfigDescription thingConfigDesc = configDescRegistry ConfigDescription thingConfigDesc = configDescRegistry
.getConfigDescription(getConfigDescriptionURI(thingUID)); .getConfigDescription(getConfigDescriptionURI(thingUID));
if (thingConfigDesc != null) { if (thingConfigDesc != null) {
@ -860,8 +762,8 @@ public class ThingResource implements RESTResource {
return ConfigUtil.normalizeTypes(properties, configDescriptions); return ConfigUtil.normalizeTypes(properties, configDescriptions);
} }
private Map<String, Object> normalizeConfiguration(Map<String, Object> properties, ChannelTypeUID channelTypeUID, private @Nullable Map<String, Object> normalizeConfiguration(Map<String, Object> properties,
ChannelUID channelUID) { ChannelTypeUID channelTypeUID, ChannelUID channelUID) {
if (properties == null || properties.isEmpty()) { if (properties == null || properties.isEmpty()) {
return properties; return properties;
} }
@ -922,14 +824,4 @@ public class ThingResource implements RESTResource {
throw new BadRequestException("Invalid URI syntax: " + uriString); 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; package org.openhab.core.io.rest.core.internal.thing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Stream; 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.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role; import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigDescription; 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.ChannelTypeRegistry;
import org.openhab.core.thing.type.ThingType; import org.openhab.core.thing.type.ThingType;
import org.openhab.core.thing.type.ThingTypeRegistry; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -94,6 +95,7 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired @JSONRequired
@Path(ThingTypeResource.PATH_THING_TYPES) @Path(ThingTypeResource.PATH_THING_TYPES)
@Api(ThingTypeResource.PATH_THING_TYPES) @Api(ThingTypeResource.PATH_THING_TYPES)
@NonNullByDefault
public class ThingTypeResource implements RESTResource { public class ThingTypeResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
@ -101,56 +103,24 @@ public class ThingTypeResource implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(ThingTypeResource.class); private final Logger logger = LoggerFactory.getLogger(ThingTypeResource.class);
private ThingTypeRegistry thingTypeRegistry; private final ChannelTypeRegistry channelTypeRegistry;
private ConfigDescriptionRegistry configDescriptionRegistry; private final ChannelGroupTypeRegistry channelGroupTypeRegistry;
private ChannelTypeRegistry channelTypeRegistry; private final ConfigDescriptionRegistry configDescriptionRegistry;
private ChannelGroupTypeRegistry channelGroupTypeRegistry; private final LocaleService localeService;
private final ThingTypeRegistry thingTypeRegistry;
private LocaleService localeService; @Activate
public ThingTypeResource( //
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) final @Reference ChannelTypeRegistry channelTypeRegistry,
protected void setThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) { final @Reference ChannelGroupTypeRegistry channelGroupTypeRegistry,
this.thingTypeRegistry = thingTypeRegistry; final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
} final @Reference LocaleService localeService, //
final @Reference 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) {
this.channelTypeRegistry = channelTypeRegistry; 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; this.channelGroupTypeRegistry = channelGroupTypeRegistry;
} this.configDescriptionRegistry = configDescriptionRegistry;
protected void unsetChannelGroupTypeRegistry(ChannelGroupTypeRegistry channelGroupTypeRegistry) {
this.channelGroupTypeRegistry = null;
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setLocaleService(LocaleService localeService) {
this.localeService = localeService; this.localeService = localeService;
} this.thingTypeRegistry = thingTypeRegistry;
protected void unsetLocaleService(LocaleService localeService) {
this.localeService = null;
} }
@GET @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") @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")) @ApiResponses(value = @ApiResponse(code = 200, message = "OK", response = StrippedThingTypeDTO.class, responseContainer = "Set"))
public Response getAll( public Response getAll(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = HttpHeaders.ACCEPT_LANGUAGE) String language, @HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") @Nullable String language,
@QueryParam("bindingId") @ApiParam(value = "filter by binding Id", required = false) @Nullable String bindingId) { @QueryParam("bindingId") @ApiParam(value = "filter by binding Id") @Nullable String bindingId) {
Locale locale = localeService.getLocale(language); Locale locale = localeService.getLocale(language);
Stream<StrippedThingTypeDTO> typeStream = thingTypeRegistry.getThingTypes(locale).stream() Stream<StrippedThingTypeDTO> typeStream = thingTypeRegistry.getThingTypes(locale).stream()
.map(t -> convertToStrippedThingTypeDTO(t, locale)); .map(thingType -> StrippedThingTypeDTOMapper.map(thingType, locale));
if (bindingId != null) { if (bindingId != null) {
typeStream = typeStream.filter(type -> type.UID.startsWith(bindingId + ':')); 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 = 200, message = "Thing type with provided thingTypeUID does not exist.", response = ThingTypeDTO.class),
@ApiResponse(code = 404, message = "No content") }) @ApiResponse(code = 404, message = "No content") })
public Response getByUID(@PathParam("thingTypeUID") @ApiParam(value = "thingTypeUID") String thingTypeUID, 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); Locale locale = localeService.getLocale(language);
ThingType thingType = thingTypeRegistry.getThingType(new ThingTypeUID(thingTypeUID), locale); ThingType thingType = thingTypeRegistry.getThingType(new ThingTypeUID(thingTypeUID), locale);
if (thingType != null) { 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; final ConfigDescription configDescription;
if (thingType.getConfigDescriptionURI() != null) { if (thingType.getConfigDescriptionURI() != null) {
configDescription = this.configDescriptionRegistry.getConfigDescription(thingType.getConfigDescriptionURI(), configDescription = this.configDescriptionRegistry.getConfigDescription(thingType.getConfigDescriptionURI(),
@ -233,21 +203,21 @@ public class ThingTypeResource implements RESTResource {
ChannelGroupType channelGroupType = channelGroupTypeRegistry ChannelGroupType channelGroupType = channelGroupTypeRegistry
.getChannelGroupType(channelGroupDefinition.getTypeUID(), locale); .getChannelGroupType(channelGroupDefinition.getTypeUID(), locale);
// Default to the channelGroupDefinition label to override the // Default to the channelGroupDefinition label/description to override the channelGroupType
// channelGroupType
String label = channelGroupDefinition.getLabel(); String label = channelGroupDefinition.getLabel();
String description = channelGroupDefinition.getDescription();
List<ChannelDefinition> channelDefinitions = Collections.emptyList();
if (channelGroupType != null) {
if (label == null) { if (label == null) {
label = channelGroupType.getLabel(); label = channelGroupType.getLabel();
} }
// Default to the channelGroupDefinition description to override the
// channelGroupType
String description = channelGroupDefinition.getDescription();
if (description == null) { if (description == null) {
description = channelGroupType.getDescription(); description = channelGroupType.getDescription();
} }
channelDefinitions = channelGroupType.getChannelDefinitions();
}
List<ChannelDefinition> channelDefinitions = channelGroupType.getChannelDefinitions();
List<ChannelDefinitionDTO> channelDefinitionDTOs = convertToChannelDefinitionDTOs(channelDefinitions, List<ChannelDefinitionDTO> channelDefinitionDTOs = convertToChannelDefinitionDTOs(channelDefinitions,
locale); locale);
@ -257,8 +227,8 @@ public class ThingTypeResource implements RESTResource {
return channelGroupDefinitionDTOs; return channelGroupDefinitionDTOs;
} }
private List<ChannelDefinitionDTO> convertToChannelDefinitionDTOs(List<ChannelDefinition> channelDefinitions, private @Nullable List<ChannelDefinitionDTO> convertToChannelDefinitionDTOs(
Locale locale) { List<ChannelDefinition> channelDefinitions, Locale locale) {
List<ChannelDefinitionDTO> channelDefinitionDTOs = new ArrayList<>(); List<ChannelDefinitionDTO> channelDefinitionDTOs = new ArrayList<>();
for (ChannelDefinition channelDefinition : channelDefinitions) { for (ChannelDefinition channelDefinition : channelDefinitions) {
ChannelType channelType = channelTypeRegistry.getChannelType(channelDefinition.getChannelTypeUID(), locale); ChannelType channelType = channelTypeRegistry.getChannelType(channelDefinition.getChannelTypeUID(), locale);
@ -289,21 +259,4 @@ public class ThingTypeResource implements RESTResource {
} }
return channelDefinitionDTOs; 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.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
@ -30,6 +29,7 @@ import org.hamcrest.core.IsCollectionContaining;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
import org.openhab.core.config.core.ConfigDescriptionRegistry;
import org.openhab.core.io.rest.LocaleServiceImpl; import org.openhab.core.io.rest.LocaleServiceImpl;
import org.openhab.core.thing.profiles.ProfileTypeRegistry; import org.openhab.core.thing.profiles.ProfileTypeRegistry;
import org.openhab.core.thing.profiles.ProfileTypeUID; import org.openhab.core.thing.profiles.ProfileTypeUID;
@ -46,25 +46,23 @@ public class ChannelTypeResourceTest {
private ChannelTypeResource channelTypeResource; private ChannelTypeResource channelTypeResource;
@Mock private @Mock ChannelTypeRegistry channelTypeRegistry;
private ChannelTypeRegistry channelTypeRegistry; private @Mock ConfigDescriptionRegistry configDescriptionRegistry;
private @Mock LocaleServiceImpl localeService;
@Mock private @Mock ProfileTypeRegistry profileTypeRegistry;
private ProfileTypeRegistry profileTypeRegistry;
@Before @Before
public void setup() { public void setup() {
initMocks(this); initMocks(this);
channelTypeResource = new ChannelTypeResource(); channelTypeResource = new ChannelTypeResource(channelTypeRegistry, configDescriptionRegistry, localeService,
channelTypeResource.setLocaleService(new LocaleServiceImpl()); profileTypeRegistry);
channelTypeResource.setChannelTypeRegistry(channelTypeRegistry);
channelTypeResource.setProfileTypeRegistry(profileTypeRegistry);
} }
@Test @Test
public void getAllShouldRetrieveAllChannelTypes() throws Exception { public void getAllShouldRetrieveAllChannelTypes() throws Exception {
when(localeService.getLocale(null)).thenReturn(Locale.ENGLISH);
channelTypeResource.getAll(null, null); channelTypeResource.getAll(null, null);
verify(channelTypeRegistry).getChannelTypes(any(Locale.class)); verify(channelTypeRegistry).getChannelTypes(Locale.ENGLISH);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -32,6 +32,8 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; 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.RESTConstants;
import org.openhab.core.io.rest.RESTResource; import org.openhab.core.io.rest.RESTResource;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
@ -62,6 +64,7 @@ import io.swagger.annotations.ApiResponses;
@Path(LogHandler.PATH_LOG) @Path(LogHandler.PATH_LOG)
@Api(LogHandler.PATH_LOG) @Api(LogHandler.PATH_LOG)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NonNullByDefault
public class LogHandler implements RESTResource { public class LogHandler implements RESTResource {
private final Logger logger = LoggerFactory.getLogger(LogHandler.class); private final Logger logger = LoggerFactory.getLogger(LogHandler.class);
@ -80,9 +83,9 @@ public class LogHandler implements RESTResource {
*/ */
public class LogMessage { public class LogMessage {
public long timestamp; public long timestamp;
public String severity; public @Nullable String severity;
public URL url; public @Nullable URL url;
public String message; public @Nullable String message;
} }
@GET @GET
@ -96,7 +99,8 @@ public class LogHandler implements RESTResource {
@ApiOperation(value = "Returns the last logged frontend messages. The amount is limited to the " @ApiOperation(value = "Returns the last logged frontend messages. The amount is limited to the "
+ LogConstants.LOG_BUFFER_LIMIT + " last entries.") + LogConstants.LOG_BUFFER_LIMIT + " last entries.")
@ApiParam(name = "limit", allowableValues = "range[1, " + LogConstants.LOG_BUFFER_LIMIT + "]") @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()) { if (logBuffer.isEmpty()) {
return Response.ok("[]").build(); 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\"}") @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"), @ApiResponses({ @ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 403, message = LogConstants.LOG_SEVERITY_IS_NOT_SUPPORTED) }) @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) { if (logMessage == null) {
logger.debug("Received null log message model!"); logger.debug("Received null log message model!");
return Response.status(500) return Response.status(500)
@ -155,7 +159,9 @@ public class LogHandler implements RESTResource {
* @return Falls if severity is not supported, true if successfully logged. * @return Falls if severity is not supported, true if successfully logged.
*/ */
private boolean doLog(LogMessage logMessage) { private boolean doLog(LogMessage logMessage) {
switch (logMessage.severity.toLowerCase()) { String severity = logMessage.severity;
severity = severity != null ? severity.toLowerCase() : "";
switch (severity) {
case "error": case "error":
logger.error(LogConstants.FRONTEND_LOG_PATTERN, logMessage.url, logMessage.message); logger.error(LogConstants.FRONTEND_LOG_PATTERN, logMessage.url, logMessage.message);
break; 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.BasicEList;
import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.events.Event; import org.openhab.core.events.Event;
import org.openhab.core.events.EventFilter; import org.openhab.core.events.EventFilter;
@ -62,6 +63,7 @@ import org.slf4j.LoggerFactory;
*/ */
@Component(service = { SitemapSubscriptionService.class, @Component(service = { SitemapSubscriptionService.class,
EventSubscriber.class }, configurationPid = "org.openhab.sitemapsubscription") EventSubscriber.class }, configurationPid = "org.openhab.sitemapsubscription")
@NonNullByDefault
public class SitemapSubscriptionService implements ModelRepositoryChangeListener, EventSubscriber { public class SitemapSubscriptionService implements ModelRepositoryChangeListener, EventSubscriber {
private static final String SITEMAP_PAGE_SEPARATOR = "#"; private static final String SITEMAP_PAGE_SEPARATOR = "#";
@ -77,7 +79,8 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
void onRelease(String subscriptionId); void onRelease(String subscriptionId);
} }
private ItemUIRegistry itemUIRegistry; private final ItemUIRegistry itemUIRegistry;
private final List<SitemapProvider> sitemapProviders = new ArrayList<>(); private final List<SitemapProvider> sitemapProviders = new ArrayList<>();
/* subscription id -> sitemap+page */ /* subscription id -> sitemap+page */
@ -95,12 +98,10 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
/* Max number of subscriptions at the same time */ /* Max number of subscriptions at the same time */
private int maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS; private int maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS;
public SitemapSubscriptionService() {
}
@Activate @Activate
protected void activate(Map<String, Object> config) { public SitemapSubscriptionService(Map<String, Object> config, final @Reference ItemUIRegistry itemUIRegistry) {
applyConfig(config); applyConfig(config);
this.itemUIRegistry = itemUIRegistry;
} }
@Deactivate @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) @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addSitemapProvider(SitemapProvider provider) { protected void addSitemapProvider(SitemapProvider provider) {
sitemapProviders.add(provider); sitemapProviders.add(provider);
@ -158,7 +150,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
* @param callback an instance that should receive the events * @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 * @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) { if (maxSubscriptions >= 0 && callbacks.size() >= maxSubscriptions) {
logger.debug("No new subscription delivered as limit ({}) is already reached", maxSubscriptions); logger.debug("No new subscription delivered as limit ({}) is already reached", maxSubscriptions);
return null; return null;
@ -206,7 +198,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
* @param subscriptionId the subscription to get the page id for * @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 * @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); String sitemapWithPageId = pageOfSubscription.get(subscriptionId);
return (sitemapWithPageId == null) ? null : extractPageId(sitemapWithPageId); 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 * @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 * @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); String sitemapWithPageId = pageOfSubscription.get(subscriptionId);
return (sitemapWithPageId == null) ? null : extractSitemapName(sitemapWithPageId); 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 // there is no listener for this page yet, so let's try to create one
listener = new PageChangeListener(sitemapName, pageId, itemUIRegistry, collectWidgets(sitemapName, pageId)); listener = new PageChangeListener(sitemapName, pageId, itemUIRegistry, collectWidgets(sitemapName, pageId));
pageChangeListeners.put(getValue(sitemapName, pageId), listener); pageChangeListeners.put(getValue(sitemapName, pageId), listener);
} } else {
if (listener != null) {
listener.addCallback(callback); listener.addCallback(callback);
} }
} }
@ -301,7 +292,7 @@ public class SitemapSubscriptionService implements ModelRepositoryChangeListener
return sitemapName + SITEMAP_PAGE_SEPARATOR + pageId; return sitemapName + SITEMAP_PAGE_SEPARATOR + pageId;
} }
private Sitemap getSitemap(String sitemapName) { private @Nullable Sitemap getSitemap(String sitemapName) {
for (SitemapProvider provider : sitemapProviders) { for (SitemapProvider provider : sitemapProviders) {
Sitemap sitemap = provider.getSitemap(sitemapName); Sitemap sitemap = provider.getSitemap(sitemapName);
if (sitemap != null) { 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.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role; import org.openhab.core.auth.Role;
import org.openhab.core.common.ThreadPoolManager; import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.io.rest.JSONResponse; import org.openhab.core.io.rest.JSONResponse;
@ -128,6 +129,7 @@ import io.swagger.annotations.ApiResponses;
@Path(SitemapResource.PATH_SITEMAPS) @Path(SitemapResource.PATH_SITEMAPS)
@RolesAllowed({ Role.USER, Role.ADMIN }) @RolesAllowed({ Role.USER, Role.ADMIN })
@Api(SitemapResource.PATH_SITEMAPS) @Api(SitemapResource.PATH_SITEMAPS)
@NonNullByDefault
public class SitemapResource public class SitemapResource
implements RESTResource, SitemapSubscriptionCallback, SseBroadcaster.Listener<SseSinkInfo> { implements RESTResource, SitemapSubscriptionCallback, SseBroadcaster.Listener<SseSinkInfo> {
@ -139,24 +141,27 @@ public class SitemapResource
private static final long TIMEOUT_IN_MS = 30000; private static final long TIMEOUT_IN_MS = 30000;
private @NonNullByDefault({}) Sse sse;
private SseBroadcaster<@NonNull SseSinkInfo> broadcaster; private SseBroadcaster<@NonNull SseSinkInfo> broadcaster;
@Context @Context
@NonNullByDefault({})
UriInfo uriInfo; UriInfo uriInfo;
@Context @Context
@NonNullByDefault({})
HttpServletRequest request; HttpServletRequest request;
@Context @Context
private HttpServletResponse response; @NonNullByDefault({})
HttpServletResponse response;
private ItemUIRegistry itemUIRegistry; @Context
@NonNullByDefault({})
Sse sse;
private SitemapSubscriptionService subscriptions; private final ItemUIRegistry itemUIRegistry;
private final SitemapSubscriptionService subscriptions;
private LocaleService localeService; private final LocaleService localeService;
private final java.util.List<SitemapProvider> sitemapProviders = new ArrayList<>(); private final java.util.List<SitemapProvider> sitemapProviders = new ArrayList<>();
@ -165,10 +170,17 @@ public class SitemapResource
private final ScheduledExecutorService scheduler = ThreadPoolManager private final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(ThreadPoolManager.THREAD_POOL_NAME_COMMON); .getScheduledPool(ThreadPoolManager.THREAD_POOL_NAME_COMMON);
private ScheduledFuture<?> cleanSubscriptionsJob; private @Nullable ScheduledFuture<?> cleanSubscriptionsJob;
@Activate @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<>(); broadcaster = new SseBroadcaster<>();
// The clean SSE subscriptions job sends an ALIVE event to all subscribers. This will trigger // 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. // The clean SSE subscriptions job is run every 5 minutes.
cleanSubscriptionsJob = scheduler.scheduleAtFixedRate(() -> { cleanSubscriptionsJob = scheduler.scheduleAtFixedRate(() -> {
logger.debug("Run clean SSE subscriptions job"); logger.debug("Run clean SSE subscriptions job");
if (subscriptions != null) {
subscriptions.checkAliveClients(); subscriptions.checkAliveClients();
}
}, 1, 5, TimeUnit.MINUTES); }, 1, 5, TimeUnit.MINUTES);
} }
@Deactivate @Deactivate
protected void deactivate() { protected void deactivate() {
if (cleanSubscriptionsJob != null && !cleanSubscriptionsJob.isCancelled()) { ScheduledFuture<?> job = cleanSubscriptionsJob;
if (job != null && !job.isCancelled()) {
logger.debug("Cancel clean SSE subscriptions job"); logger.debug("Cancel clean SSE subscriptions job");
cleanSubscriptionsJob.cancel(true); job.cancel(true);
cleanSubscriptionsJob = null; cleanSubscriptionsJob = null;
} }
broadcaster.close(); 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) @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
public void addSitemapProvider(SitemapProvider provider) { public void addSitemapProvider(SitemapProvider provider) {
sitemapProviders.add(provider); sitemapProviders.add(provider);
@ -227,15 +215,6 @@ public class SitemapResource
sitemapProviders.remove(provider); 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 @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all available sitemaps.", response = SitemapDTO.class, responseContainer = "Collection") @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) @ApiOperation(value = "Get sitemap by name.", response = SitemapDTO.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK") })
public Response getSitemapData(@Context HttpHeaders headers, 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, @PathParam("sitemapname") @ApiParam(value = "sitemap name") String sitemapname,
@QueryParam("type") String type, @QueryParam("jsoncallback") @DefaultValue("callback") String callback, @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); final Locale locale = localeService.getLocale(language);
logger.debug("Received HTTP GET request from IP {} at '{}' for media type '{}'.", request.getRemoteAddr(), logger.debug("Received HTTP GET request from IP {} at '{}' for media type '{}'.", request.getRemoteAddr(),
uriInfo.getPath(), type); 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 = 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.") }) @ApiResponse(code = 400, message = "Invalid subscription id has been provided.") })
public Response getPageData(@Context HttpHeaders headers, 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("sitemapname") @ApiParam(value = "sitemap name") String sitemapname,
@PathParam("pageid") @ApiParam(value = "page id") String pageId, @PathParam("pageid") @ApiParam(value = "page id") String pageId,
@QueryParam("subscriptionid") @ApiParam(value = "subscriptionid", required = false) String subscriptionId, @QueryParam("subscriptionid") @ApiParam(value = "subscriptionid") @Nullable String subscriptionId,
@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); final Locale locale = localeService.getLocale(language);
logger.debug("Received HTTP GET request from IP {} at '{}'", request.getRemoteAddr(), uriInfo.getPath()); 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.") }) @ApiResponse(code = 404, message = "Subscription not found.") })
public void getSitemapEvents(@Context final SseEventSink sseEventSink, @Context final HttpServletResponse response, public void getSitemapEvents(@Context final SseEventSink sseEventSink, @Context final HttpServletResponse response,
@PathParam("subscriptionid") @ApiParam(value = "subscription id") String subscriptionId, @PathParam("subscriptionid") @ApiParam(value = "subscription id") String subscriptionId,
@QueryParam("sitemap") @ApiParam(value = "sitemap name", required = false) String sitemapname, @QueryParam("sitemap") @ApiParam(value = "sitemap name") @Nullable String sitemapname,
@QueryParam("pageid") @ApiParam(value = "page id", required = false) String pageId) { @QueryParam("pageid") @ApiParam(value = "page id") @Nullable String pageId) {
final SseSinkInfo sinkInfo = knownSubscriptions.get(subscriptionId); final SseSinkInfo sinkInfo = knownSubscriptions.get(subscriptionId);
if (sinkInfo == null) { if (sinkInfo == null) {
logger.debug("Subscription id {} does not exist.", subscriptionId); logger.debug("Subscription id {} does not exist.", subscriptionId);
@ -475,8 +454,9 @@ public class SitemapResource
return bean; return bean;
} }
private PageDTO createPageBean(String sitemapName, String title, String icon, String pageId, EList<Widget> children, private PageDTO createPageBean(String sitemapName, @Nullable String title, @Nullable String icon, String pageId,
boolean drillDown, boolean isLeaf, URI uri, Locale locale, boolean timeout, boolean includeHiddenWidgets) { @Nullable EList<Widget> children, boolean drillDown, boolean isLeaf, URI uri, Locale locale,
boolean timeout, boolean includeHiddenWidgets) {
PageDTO bean = new PageDTO(); PageDTO bean = new PageDTO();
bean.timeout = timeout; bean.timeout = timeout;
bean.id = pageId; bean.id = pageId;
@ -499,8 +479,8 @@ public class SitemapResource
return bean; return bean;
} }
private WidgetDTO createWidgetBean(String sitemapName, Widget widget, boolean drillDown, URI uri, String widgetId, private @Nullable WidgetDTO createWidgetBean(String sitemapName, Widget widget, boolean drillDown, URI uri,
Locale locale, boolean evenIfHidden) { String widgetId, Locale locale, boolean evenIfHidden) {
// Test visibility // Test visibility
if (!evenIfHidden && !itemUIRegistry.getVisiblity(widget)) { if (!evenIfHidden && !itemUIRegistry.getVisiblity(widget)) {
return null; return null;
@ -653,7 +633,7 @@ public class SitemapResource
return true; return true;
} }
private Sitemap getSitemap(String sitemapname) { private @Nullable Sitemap getSitemap(String sitemapname) {
for (SitemapProvider provider : sitemapProviders) { for (SitemapProvider provider : sitemapProviders) {
Sitemap sitemap = provider.getSitemap(sitemapname); Sitemap sitemap = provider.getSitemap(sitemapname);
if (sitemap != null) { if (sitemap != null) {
@ -723,7 +703,6 @@ public class SitemapResource
*/ */
private Set<GenericItem> getAllItems(EList<Widget> widgets) { private Set<GenericItem> getAllItems(EList<Widget> widgets) {
Set<GenericItem> items = new HashSet<>(); Set<GenericItem> items = new HashSet<>();
if (itemUIRegistry != null) {
for (Widget widget : widgets) { for (Widget widget : widgets) {
// We skip the chart widgets having a refresh argument // We skip the chart widgets having a refresh argument
boolean skipWidget = false; boolean skipWidget = false;
@ -751,7 +730,6 @@ public class SitemapResource
items.addAll(getItemsInColorCond(widget.getLabelColor())); items.addAll(getItemsInColorCond(widget.getLabelColor()));
items.addAll(getItemsInColorCond(widget.getValueColor())); items.addAll(getItemsInColorCond(widget.getValueColor()));
} }
}
return items; return items;
} }
@ -858,11 +836,6 @@ public class SitemapResource
knownSubscriptions.remove(subscriptionId); knownSubscriptions.remove(subscriptionId);
} }
@Override
public boolean isSatisfied() {
return itemUIRegistry != null && subscriptions != null && localeService != null;
}
@Override @Override
public void sseEventSinkRemoved(SseEventSink sink, SseSinkInfo info) { public void sseEventSinkRemoved(SseEventSink sink, SseSinkInfo info) {
logger.debug("SSE connection for subscription {} has been closed.", info.subscriptionId); 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.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
import org.openhab.core.io.rest.LocaleService; 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.GenericItem;
import org.openhab.core.items.ItemNotFoundException; import org.openhab.core.items.ItemNotFoundException;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
@ -79,23 +80,14 @@ public class SitemapResourceTest extends JavaTest {
private SitemapResource sitemapResource; private SitemapResource sitemapResource;
@Mock private @Mock HttpHeaders headers;
private UriInfo uriInfo; private @Mock Sitemap defaultSitemap;
private @Mock ItemUIRegistry itemUIRegistry;
@Mock private @Mock LocaleService localeService;
private HttpServletRequest request; private @Mock HttpServletRequest request;
private @Mock SitemapProvider sitemapProvider;
@Mock private @Mock SitemapSubscriptionService subscriptions;
private SitemapProvider sitemapProvider; private @Mock UriInfo uriInfo;
@Mock
private Sitemap defaultSitemap;
@Mock
private ItemUIRegistry itemUIRegistry;
@Mock
private HttpHeaders headers;
private GenericItem item; private GenericItem item;
private GenericItem visibilityRuleItem; private GenericItem visibilityRuleItem;
@ -107,7 +99,8 @@ public class SitemapResourceTest extends JavaTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
initMocks(this); initMocks(this);
sitemapResource = new SitemapResource();
sitemapResource = new SitemapResource(itemUIRegistry, localeService, subscriptions);
when(uriInfo.getAbsolutePathBuilder()).thenReturn(UriBuilder.fromPath(SITEMAP_PATH)); when(uriInfo.getAbsolutePathBuilder()).thenReturn(UriBuilder.fromPath(SITEMAP_PATH));
when(uriInfo.getBaseUriBuilder()).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); labelColorItem = new TestItem(LABEL_COLOR_ITEM_NAME);
valueColorItem = new TestItem(VALUE_COLOR_ITEM_NAME); valueColorItem = new TestItem(VALUE_COLOR_ITEM_NAME);
LocaleService localeService = mock(LocaleService.class);
when(localeService.getLocale(null)).thenReturn(Locale.US); when(localeService.getLocale(null)).thenReturn(Locale.US);
sitemapResource.setLocaleService(localeService);
configureSitemapProviderMock(); configureSitemapProviderMock();
configureSitemapMock(); configureSitemapMock();
@ -131,7 +122,6 @@ public class SitemapResourceTest extends JavaTest {
widgets = initSitemapWidgets(); widgets = initSitemapWidgets();
configureItemUIRegistry(PercentType.HUNDRED, OnOffType.ON); configureItemUIRegistry(PercentType.HUNDRED, OnOffType.ON);
sitemapResource.setItemUIRegistry(itemUIRegistry);
// Disable long polling // Disable long polling
when(headers.getRequestHeader(HTTP_HEADER_X_ATMOSPHERE_TRANSPORT)).thenReturn(null); 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 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 SseBroadcaster<SseSinkItemInfo> itemStatesBroadcaster = new SseBroadcaster<>();
private final SseItemStatesEventBuilder itemStatesEventBuilder; private final SseItemStatesEventBuilder itemStatesEventBuilder;
@ -103,11 +103,6 @@ public class SseResource implements SsePublisher {
private ExecutorService executorService; private ExecutorService executorService;
@Context
public void setSse(final Sse sse) {
this.sse = sse;
}
@Activate @Activate
public SseResource(@Reference SseItemStatesEventBuilder itemStatesEventBuilder) { public SseResource(@Reference SseItemStatesEventBuilder itemStatesEventBuilder) {
this.executorService = Executors.newSingleThreadExecutor(); this.executorService = Executors.newSingleThreadExecutor();

View File

@ -23,12 +23,11 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; 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.auth.Role;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; 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.components.UIComponentRegistryFactory;
import org.openhab.core.ui.tiles.Tile; import org.openhab.core.ui.tiles.Tile;
import org.openhab.core.ui.tiles.TileProvider; 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.Component;
import org.osgi.service.component.annotations.Reference; 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.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired; import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
@ -67,16 +65,22 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired @JSONRequired
@Path(UIResource.PATH_UI) @Path(UIResource.PATH_UI)
@Api(UIResource.PATH_UI) @Api(UIResource.PATH_UI)
@NonNullByDefault
public class UIResource implements RESTResource { public class UIResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_UI = "ui"; public static final String PATH_UI = "ui";
@Context private final UIComponentRegistryFactory componentRegistryFactory;
private UriInfo uriInfo; private final TileProvider tileProvider;
private TileProvider tileProvider; @Activate
private UIComponentRegistryFactory componentRegistryFactory; public UIResource( //
final @Reference UIComponentRegistryFactory componentRegistryFactory,
final @Reference TileProvider tileProvider) {
this.componentRegistryFactory = componentRegistryFactory;
this.tileProvider = tileProvider;
}
@GET @GET
@Path("/tiles") @Path("/tiles")
@ -169,29 +173,6 @@ public class UIResource implements RESTResource {
return Response.ok().build(); 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) { private TileDTO toTileDTO(Tile tile) {
return new TileDTO(tile.getName(), tile.getUrl(), tile.getOverlay(), tile.getImageUrl()); 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.Locale;
import java.util.Set; import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.voice.text.HumanLanguageInterpreter; import org.openhab.core.voice.text.HumanLanguageInterpreter;
/** /**
@ -23,6 +24,7 @@ import org.openhab.core.voice.text.HumanLanguageInterpreter;
* *
* @author Kai Kreuzer - Initial contribution * @author Kai Kreuzer - Initial contribution
*/ */
@NonNullByDefault
public class HLIMapper { public class HLIMapper {
/** /**

View File

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

View File

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

View File

@ -20,16 +20,17 @@ import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam; import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; 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.LocaleService;
import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTConstants;
import org.openhab.core.io.rest.RESTResource; import org.openhab.core.io.rest.RESTResource;
import org.openhab.core.ui.icon.IconProvider; import org.openhab.core.ui.icon.IconProvider;
import org.openhab.core.ui.icon.IconSet; 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.Component;
import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality; 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.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses; import io.swagger.annotations.ApiResponses;
@ -58,14 +60,20 @@ import io.swagger.annotations.ApiResponses;
@JSONRequired @JSONRequired
@Path(IconSetResource.PATH_ICONSETS) @Path(IconSetResource.PATH_ICONSETS)
@Api(IconSetResource.PATH_ICONSETS) @Api(IconSetResource.PATH_ICONSETS)
@NonNullByDefault
public class IconSetResource implements RESTResource { public class IconSetResource implements RESTResource {
/** The URI path to this resource */ /** The URI path to this resource */
public static final String PATH_ICONSETS = "iconsets"; 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) @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addIconProvider(IconProvider iconProvider) { protected void addIconProvider(IconProvider iconProvider) {
@ -76,23 +84,11 @@ public class IconSetResource implements RESTResource {
this.iconProviders.remove(iconProvider); 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 @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets all icon sets.") @ApiOperation(value = "Gets all icon sets.")
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK") }) @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); Locale locale = localeService.getLocale(language);
List<IconSet> iconSets = new ArrayList<>(iconProviders.size()); 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.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any; 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;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.config.core.ConfigDescriptionRegistry; import org.openhab.core.config.core.ConfigDescriptionRegistry;
import org.openhab.core.config.discovery.inbox.Inbox; import org.openhab.core.config.discovery.inbox.Inbox;
import org.openhab.core.test.java.JavaOSGiTest; 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 Thing testThing = ThingBuilder.create(testTypeUID, testUID).build();
private final String testThingLabel = "dummy_thing"; private final String testThingLabel = "dummy_thing";
private @Mock Inbox inbox;
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
ConfigDescriptionRegistry configDescRegistry = getService(ConfigDescriptionRegistry.class); initMocks(this);
assertFalse(configDescRegistry == null);
registerService(new InboxResource(), InboxResource.class.getName()); ConfigDescriptionRegistry configDescRegistry = getService(ConfigDescriptionRegistry.class);
assertNotNull(configDescRegistry);
registerService(new InboxResource(inbox), InboxResource.class.getName());
resource = getService(InboxResource.class); resource = getService(InboxResource.class);
assertFalse(resource == null); assertNotNull(resource);
} }
@Test @Test
public void assertThatApproveApprovesThingsWhichAreInTheInbox() { public void assertThatApproveApprovesThingsWhichAreInTheInbox() {
Inbox inbox = mock(Inbox.class);
when(inbox.approve(any(), any())).thenReturn(testThing); when(inbox.approve(any(), any())).thenReturn(testThing);
resource.setInbox(inbox);
Response reponse = resource.approve(null, testThing.getUID().toString(), testThingLabel); Response reponse = resource.approve(null, testThing.getUID().toString(), testThingLabel);
assertTrue(reponse.getStatusInfo().getStatusCode() == Status.OK.getStatusCode()); assertTrue(reponse.getStatusInfo().getStatusCode() == Status.OK.getStatusCode());
} }
@Test @Test
public void assertThatApproveDoesntApproveThingsWhichAreNotInTheInbox() { public void assertThatApproveDoesntApproveThingsWhichAreNotInTheInbox() {
Inbox inbox = mock(Inbox.class);
when(inbox.approve(any(), any())).thenThrow(new IllegalArgumentException()); when(inbox.approve(any(), any())).thenThrow(new IllegalArgumentException());
resource.setInbox(inbox);
Response reponse = resource.approve(null, testThing.getUID().toString(), testThingLabel); Response reponse = resource.approve(null, testThing.getUID().toString(), testThingLabel);
assertTrue(reponse.getStatusInfo().getStatusCode() == Status.NOT_FOUND.getStatusCode()); 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.StringItem;
import org.openhab.core.library.items.SwitchItem; import org.openhab.core.library.items.SwitchItem;
import org.openhab.core.test.java.JavaOSGiTest; import org.openhab.core.test.java.JavaOSGiTest;
import org.openhab.core.test.storage.VolatileStorageService;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
@ -72,8 +73,7 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
private GenericItem item3; private GenericItem item3;
private GenericItem item4; private GenericItem item4;
@Mock private @Mock ItemProvider itemProvider;
private ItemProvider itemProvider;
private UriInfo uriInfo; private UriInfo uriInfo;
private HttpHeaders httpHeaders; private HttpHeaders httpHeaders;
@ -85,6 +85,8 @@ public class ItemResourceOSGiTest extends JavaOSGiTest {
public void setup() { public void setup() {
initMocks(this); initMocks(this);
registerService(new VolatileStorageService());
itemResource = getService(RESTResource.class, ItemResource.class); itemResource = getService(RESTResource.class, ItemResource.class);
assertNotNull(itemResource); 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.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -23,7 +24,10 @@ import java.util.TimeZone;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock;
import org.openhab.core.i18n.TimeZoneProvider; 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.library.types.OnOffType;
import org.openhab.core.persistence.HistoricItem; import org.openhab.core.persistence.HistoricItem;
import org.openhab.core.persistence.PersistenceServiceRegistry; import org.openhab.core.persistence.PersistenceServiceRegistry;
@ -44,9 +48,16 @@ public class PersistenceResourceTest {
private PersistenceResource pResource; private PersistenceResource pResource;
private List<HistoricItem> items; private List<HistoricItem> items;
private @Mock ItemRegistry itemRegistry;
private @Mock LocaleService localeService;
private @Mock PersistenceServiceRegistry persistenceServiceRegistry;
private @Mock TimeZoneProvider timeZoneProvider;
@Before @Before
public void setup() { public void setup() {
pResource = new PersistenceResource(); initMocks(this);
pResource = new PersistenceResource(itemRegistry, localeService, persistenceServiceRegistry, timeZoneProvider);
int startValue = 2016; int startValue = 2016;
int endValue = 2018; int endValue = 2018;
@ -78,20 +89,12 @@ public class PersistenceResourceTest {
QueryablePersistenceService pService = mock(QueryablePersistenceService.class); QueryablePersistenceService pService = mock(QueryablePersistenceService.class);
when(pService.query(any())).thenReturn(items); 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()); 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 @Test
public void testGetPersistenceItemData() { 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); ItemHistoryDTO dto = pResource.createDTO(PERSISTENCE_SERVICE_ID, "testItem", null, null, 1, 5, false);
assertEquals(5, Integer.parseInt(dto.datapoints)); 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.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any; 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.ArrayList;
import java.util.List; import java.util.List;
@ -24,6 +25,8 @@ import java.util.stream.Stream;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.test.java.JavaTest;
import org.openhab.core.thing.profiles.ProfileType; import org.openhab.core.thing.profiles.ProfileType;
import org.openhab.core.thing.profiles.ProfileTypeBuilder; import org.openhab.core.thing.profiles.ProfileTypeBuilder;
@ -42,7 +45,7 @@ import org.openhab.core.thing.type.ChannelTypeUID;
*/ */
public class ProfileTypeResourceTest extends JavaTest { public class ProfileTypeResourceTest extends JavaTest {
private ProfileTypeResource ressource; private ProfileTypeResource resource;
// UIDs for state profile types // UIDs for state profile types
private final ProfileTypeUID stateProfileTypeUID1 = new ProfileTypeUID("my:stateProfile1"); private final ProfileTypeUID stateProfileTypeUID1 = new ProfileTypeUID("my:stateProfile1");
@ -67,12 +70,15 @@ public class ProfileTypeResourceTest extends JavaTest {
private final ChannelType otherTriggerChannelType = ChannelTypeBuilder private final ChannelType otherTriggerChannelType = ChannelTypeBuilder
.trigger(otherTriggerChannelTypeUID, "channel1").build(); .trigger(otherTriggerChannelTypeUID, "channel1").build();
private @Mock ChannelTypeRegistry channelTypeRegistry;
private @Mock LocaleService localeService;
private @Mock ProfileTypeRegistry profileTypeRegistry;
@Before @Before
public void setup() { public void setup() {
ressource = new ProfileTypeResource(); initMocks(this);
ChannelTypeRegistry ctRegistry = mock(ChannelTypeRegistry.class); resource = new ProfileTypeResource(channelTypeRegistry, localeService, profileTypeRegistry);
ProfileTypeRegistry ptRegistry = mock(ProfileTypeRegistry.class);
List<ProfileType> profileTypes = new ArrayList<>(); List<ProfileType> profileTypes = new ArrayList<>();
ProfileType pt1 = ProfileTypeBuilder.newState(stateProfileTypeUID1, "profile1") ProfileType pt1 = ProfileTypeBuilder.newState(stateProfileTypeUID1, "profile1")
@ -87,20 +93,17 @@ public class ProfileTypeResourceTest extends JavaTest {
profileTypes.add(pt3); profileTypes.add(pt3);
profileTypes.add(pt4); profileTypes.add(pt4);
when(ptRegistry.getProfileTypes(any())).thenReturn(profileTypes); when(profileTypeRegistry.getProfileTypes(any())).thenReturn(profileTypes);
when(ctRegistry.getChannelType(pt1ChannelType1UID, null)).thenReturn(pt1ChannelType1); when(channelTypeRegistry.getChannelType(pt1ChannelType1UID, null)).thenReturn(pt1ChannelType1);
when(ctRegistry.getChannelType(pt3ChannelType1UID, null)).thenReturn(pt3ChannelType1); when(channelTypeRegistry.getChannelType(pt3ChannelType1UID, null)).thenReturn(pt3ChannelType1);
when(ctRegistry.getChannelType(otherStateChannelTypeUID, null)).thenReturn(otherStateChannelType); when(channelTypeRegistry.getChannelType(otherStateChannelTypeUID, null)).thenReturn(otherStateChannelType);
when(ctRegistry.getChannelType(otherTriggerChannelTypeUID, null)).thenReturn(otherTriggerChannelType); when(channelTypeRegistry.getChannelType(otherTriggerChannelTypeUID, null)).thenReturn(otherTriggerChannelType);
ressource.setChannelTypeRegistry(ctRegistry);
ressource.setProfileTypeRegistry(ptRegistry);
} }
@Test @Test
public void testGetAll() { 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()); List<ProfileTypeDTO> list = result.collect(Collectors.toList());
assertThat(list.size(), is(4)); assertThat(list.size(), is(4));
@ -108,7 +111,7 @@ public class ProfileTypeResourceTest extends JavaTest {
@Test @Test
public void testGetProfileTypesForStateChannel1() { 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()); 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 // 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 @Test
public void testGetProfileTypesForOtherChannel() { 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()); 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 // 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 @Test
public void testGetProfileTypesForTriggerChannel1() { 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()); List<ProfileTypeDTO> list = result.collect(Collectors.toList());
// should be both trigger profiles because the second trigger profile supports ALL channel types // should be both trigger profiles because the second trigger profile supports ALL channel types
@ -149,7 +152,7 @@ public class ProfileTypeResourceTest extends JavaTest {
@Test @Test
public void testGetProfileTypesForTriggerChannel2() { 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()); 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 // should be only the second trigger profile because the first one is restricted to another channel type UID