110110import org .slf4j .Logger ;
111111import org .slf4j .LoggerFactory ;
112112
113- import com .google .gson .Gson ;
114113import com .google .gson .JsonObject ;
115114
116115import io .swagger .v3 .oas .annotations .Operation ;
@@ -182,8 +181,6 @@ private static void respectForwarded(final UriBuilder uriBuilder, final @Context
182181 }
183182
184183 private final Logger logger = LoggerFactory .getLogger (ItemResource .class );
185- private final Gson gson = new Gson ();
186-
187184 private final DTOMapper dtoMapper ;
188185 private final EventPublisher eventPublisher ;
189186 private final ItemBuilderFactory itemBuilderFactory ;
@@ -500,7 +497,7 @@ private Response sendItemStateInternal(@Nullable String language, String itemNam
500497 final Locale locale = localeService .getLocale (language );
501498 final ZoneId zoneId = timeZoneProvider .getTimeZone ();
502499
503- source = buildSource (source , securityContext );
500+ String eventSource = buildSource (source , securityContext );
504501
505502 // get Item
506503 Item item = getItem (itemName );
@@ -512,7 +509,7 @@ private Response sendItemStateInternal(@Nullable String language, String itemNam
512509
513510 if (state != null ) {
514511 // set State and report OK
515- eventPublisher .post (ItemEventFactory .createStateEvent (itemName , state , source ));
512+ eventPublisher .post (ItemEventFactory .createStateEvent (itemName , state , eventSource ));
516513 return getItemResponse (null , Status .ACCEPTED , null , locale , zoneId , null );
517514 } else {
518515 // State could not be parsed
@@ -566,7 +563,7 @@ private Response sendItemCommandInternal(String itemName, String value, @Nullabl
566563 SecurityContext securityContext ) {
567564 Item item = getItem (itemName );
568565 Command command = null ;
569- source = buildSource (source , securityContext );
566+ String eventSource = buildSource (source , securityContext );
570567 if (item != null ) {
571568 if ("toggle" .equalsIgnoreCase (value ) && (item instanceof SwitchItem || item instanceof RollershutterItem )) {
572569 if (OnOffType .ON .equals (item .getStateAs (OnOffType .class ))) {
@@ -585,7 +582,7 @@ private Response sendItemCommandInternal(String itemName, String value, @Nullabl
585582 command = TypeParser .parseCommand (item .getAcceptedCommandTypes (), value );
586583 }
587584 if (command != null ) {
588- eventPublisher .post (ItemEventFactory .createCommandEvent (itemName , command , source ));
585+ eventPublisher .post (ItemEventFactory .createCommandEvent (itemName , command , eventSource ));
589586 ResponseBuilder resbuilder = Response .ok ();
590587 resbuilder .type (MediaType .TEXT_PLAIN );
591588 return resbuilder .build ();
@@ -750,7 +747,8 @@ public Response removeTag(@PathParam("itemName") @Parameter(description = "item
750747 @ ApiResponse (responseCode = "200" , description = "OK" ), //
751748 @ ApiResponse (responseCode = "201" , description = "Created" ), //
752749 @ ApiResponse (responseCode = "404" , description = "Item not found." ), //
753- @ ApiResponse (responseCode = "405" , description = "Metadata not editable." ) })
750+ @ ApiResponse (responseCode = "405" , description = "Metadata not editable." ),
751+ @ ApiResponse (responseCode = "503" , description = "Managed provider not available." ) })
754752 public Response addMetadata (@ PathParam ("itemName" ) @ Parameter (description = "item name" ) String itemName ,
755753 @ PathParam ("namespace" ) @ Parameter (description = "namespace" ) String namespace ,
756754 @ Parameter (description = "metadata" , required = true ) MetadataDTO metadata ) {
@@ -767,45 +765,81 @@ public Response addMetadata(@PathParam("itemName") @Parameter(description = "ite
767765
768766 MetadataKey key = new MetadataKey (namespace , itemName );
769767 Metadata md = new Metadata (key , value , metadata .config );
770- if (metadataRegistry .get (key ) == null ) {
771- metadataRegistry .add (md );
772- return Response .status (Status .CREATED ).type (MediaType .TEXT_PLAIN ).build ();
773- } else {
774- metadataRegistry .update (md );
775- return Response .ok (null , MediaType .TEXT_PLAIN ).build ();
768+ try {
769+ if (metadataRegistry .get (key ) == null ) {
770+ metadataRegistry .add (md );
771+ return Response .status (Status .CREATED ).type (MediaType .TEXT_PLAIN ).build ();
772+ } else {
773+ if (metadataRegistry .update (md ) == null ) {
774+ // Exists, but not managed
775+ return Response .status (Status .METHOD_NOT_ALLOWED ).build ();
776+ }
777+ return Response .ok (null , MediaType .TEXT_PLAIN ).build ();
778+ }
779+ } catch (UnsupportedOperationException e ) {
780+ // Trying to add to a reserved namespace that is in an unmanaged provider
781+ return JSONResponse .createErrorResponse (Status .METHOD_NOT_ALLOWED , e .getMessage ());
782+ } catch (IllegalStateException e ) {
783+ // There is no managed provider available
784+ return Response .status (Status .SERVICE_UNAVAILABLE ).build ();
785+ }
786+ }
787+
788+ @ DELETE
789+ @ RolesAllowed ({ Role .ADMIN })
790+ @ Path ("/{itemName: [a-zA-Z_0-9]+}/metadata" )
791+ @ Operation (operationId = "removeAllMetadataFromItem" , summary = "Removes all managed metadata from an item." , security = {
792+ @ SecurityRequirement (name = "oauth2" , scopes = { "admin" }) }, responses = {
793+ @ ApiResponse (responseCode = "200" , description = "OK" ),
794+ @ ApiResponse (responseCode = "404" , description = "Item not found." ) })
795+ public Response removeAllMetadata (@ PathParam ("itemName" ) @ Parameter (description = "item name" ) String itemName ) {
796+ Item item = getItem (itemName );
797+
798+ if (item == null ) {
799+ return Response .status (Status .NOT_FOUND ).build ();
776800 }
801+
802+ metadataRegistry .removeItemMetadata (itemName );
803+ return Response .ok (null , MediaType .TEXT_PLAIN ).build ();
777804 }
778805
779806 @ DELETE
780807 @ RolesAllowed ({ Role .ADMIN })
781808 @ Path ("/{itemName: [a-zA-Z_0-9]+}/metadata/{namespace}" )
782- @ Operation (operationId = "removeMetadataFromItem" , summary = "Removes metadata from an item." , security = {
809+ @ Operation (operationId = "removeMetadataFromItem" , summary = "Removes metadata in a specific namespace from an item." , security = {
783810 @ SecurityRequirement (name = "oauth2" , scopes = { "admin" }) }, responses = {
784811 @ ApiResponse (responseCode = "200" , description = "OK" ),
785- @ ApiResponse (responseCode = "404" , description = "Item not found." ),
786- @ ApiResponse (responseCode = "405" , description = "Meta data not editable." ) })
812+ @ ApiResponse (responseCode = "404" , description = "Item or namespace not found." ),
813+ @ ApiResponse (responseCode = "405" , description = "Metadata not editable." ),
814+ @ ApiResponse (responseCode = "503" , description = "Managed provider not available." ) })
787815 public Response removeMetadata (@ PathParam ("itemName" ) @ Parameter (description = "item name" ) String itemName ,
788- @ Nullable @ PathParam ("namespace" ) @ Parameter (description = "namespace" ) String namespace ) {
816+ @ PathParam ("namespace" ) @ Parameter (description = "namespace" ) String namespace ) {
789817 Item item = getItem (itemName );
790818
791819 if (item == null ) {
792820 return Response .status (Status .NOT_FOUND ).build ();
793821 }
794822
795- if (namespace == null ) {
796- metadataRegistry .removeItemMetadata (itemName );
797- } else {
798- MetadataKey key = new MetadataKey (namespace , itemName );
823+ MetadataKey key = new MetadataKey (namespace , itemName );
824+ try {
799825 if (metadataRegistry .get (key ) != null ) {
800- if (metadataRegistry .remove (key ) == null ) {
801- return Response .status (Status .CONFLICT ).build ();
826+ Metadata removedMetadata = metadataRegistry .remove (key );
827+ if (removedMetadata != null ) {
828+ return Response .ok (null , MediaType .TEXT_PLAIN ).build ();
829+ }
830+ if (metadataRegistry .get (key ) != null ) {
831+ // Exists, but not managed, and not removed in the mean time
832+ return Response .status (Status .METHOD_NOT_ALLOWED ).build ();
802833 }
803- } else {
804- return Response .status (Status .NOT_FOUND ).build ();
805834 }
835+ return Response .status (Status .NOT_FOUND ).build ();
836+ } catch (UnsupportedOperationException e ) {
837+ // Trying to remove from a reserved namespace that is in an unmanaged provider
838+ return JSONResponse .createErrorResponse (Status .METHOD_NOT_ALLOWED , e .getMessage ());
839+ } catch (IllegalStateException e ) {
840+ // There is no managed provider available
841+ return Response .status (Status .SERVICE_UNAVAILABLE ).build ();
806842 }
807-
808- return Response .ok (null , MediaType .TEXT_PLAIN ).build ();
809843 }
810844
811845 @ POST
@@ -818,8 +852,13 @@ public Response purge() {
818852 Collection <String > itemNames = itemRegistry .stream ().map (Item ::getName )
819853 .collect (Collectors .toCollection (HashSet ::new ));
820854
821- metadataRegistry .getAll ().stream ().filter (md -> !itemNames .contains (md .getUID ().getItemName ()))
822- .forEach (md -> metadataRegistry .remove (md .getUID ()));
855+ metadataRegistry .getAll ().stream ().filter (md -> !itemNames .contains (md .getUID ().getItemName ())).forEach (md -> {
856+ try {
857+ metadataRegistry .remove (md .getUID ());
858+ } catch (UnsupportedOperationException | IllegalStateException e ) {
859+ // ignore metadata that cannot be removed
860+ }
861+ });
823862 return Response .ok ().build ();
824863 }
825864
0 commit comments