1 package de.dlr.shepard.common.subscription.endpoints; 2 3 import de.dlr.shepard.common.subscription.entities.Subscription; 4 import de.dlr.shepard.common.subscription.io.EventIO; 5 import de.dlr.shepard.common.subscription.io.SubscriptionIO; 6 import de.dlr.shepard.common.subscription.services.SubscriptionService; 7 import de.dlr.shepard.common.util.Constants; 8 import jakarta.enterprise.context.RequestScoped; 9 import jakarta.inject.Inject; 10 import jakarta.validation.Valid; 11 import jakarta.validation.constraints.NotBlank; 12 import jakarta.validation.constraints.NotNull; 13 import jakarta.validation.constraints.PositiveOrZero; 14 import jakarta.ws.rs.Consumes; 15 import jakarta.ws.rs.DELETE; 16 import jakarta.ws.rs.GET; 17 import jakarta.ws.rs.POST; 18 import jakarta.ws.rs.Path; 19 import jakarta.ws.rs.PathParam; 20 import jakarta.ws.rs.Produces; 21 import jakarta.ws.rs.core.MediaType; 22 import jakarta.ws.rs.core.Response; 23 import jakarta.ws.rs.core.Response.Status; 24 import java.util.ArrayList; 25 import org.eclipse.microprofile.openapi.annotations.Operation; 26 import org.eclipse.microprofile.openapi.annotations.callbacks.Callback; 27 import org.eclipse.microprofile.openapi.annotations.callbacks.CallbackOperation; 28 import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; 29 import org.eclipse.microprofile.openapi.annotations.links.Link; 30 import org.eclipse.microprofile.openapi.annotations.links.LinkParameter; 31 import org.eclipse.microprofile.openapi.annotations.media.Content; 32 import org.eclipse.microprofile.openapi.annotations.media.Schema; 33 import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; 34 import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; 35 import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; 36 import org.eclipse.microprofile.openapi.annotations.tags.Tag; 37 38 @Produces(MediaType.APPLICATION_JSON) 39 @Consumes(MediaType.APPLICATION_JSON) 40 @Path(Constants.USERS + "/{" + Constants.USERNAME + "}/" + Constants.SUBSCRIPTIONS) 41 @RequestScoped 42 public class SubscriptionRest { 43 44 @Inject 45 SubscriptionService subscriptionService; 46 47 @GET 48 @Tag(name = Constants.SUBSCRIPTION) 49 @Operation(description = "Get all subscriptions") 50 @APIResponse( 51 description = "ok", 52 responseCode = "200", 53 content = @Content(schema = @Schema(type = SchemaType.ARRAY, implementation = SubscriptionIO.class)) 54 ) 55 @APIResponse(responseCode = "400", description = "bad request") 56 @APIResponse(responseCode = "401", description = "not authorized") 57 @APIResponse(responseCode = "403", description = "forbidden") 58 @APIResponse(responseCode = "404", description = "not found") 59 @Parameter(name = Constants.USERNAME) 60 public Response getAllSubscriptions(@PathParam(Constants.USERNAME) @NotBlank String username) { 61 var subscriptions = subscriptionService.getAllSubscriptions(username); 62 var result = new ArrayList<SubscriptionIO>(subscriptions.size()); 63 for (var sub : subscriptions) { 64 result.add(new SubscriptionIO(sub)); 65 } 66 return Response.ok(result).build(); 67 } 68 69 @GET 70 @Path("/{" + Constants.SUBSCRIPTION_ID + "}") 71 @Tag(name = Constants.SUBSCRIPTION) 72 @Operation(description = "Get subscription") 73 @APIResponse( 74 description = "ok", 75 responseCode = "200", 76 content = @Content(schema = @Schema(implementation = SubscriptionIO.class)) 77 ) 78 @APIResponse(responseCode = "400", description = "bad request") 79 @APIResponse(responseCode = "401", description = "not authorized") 80 @APIResponse(responseCode = "403", description = "forbidden") 81 @APIResponse(responseCode = "404", description = "not found") 82 @Parameter(name = Constants.USERNAME) 83 @Parameter(name = Constants.SUBSCRIPTION_ID) 84 public Response getSubscription( 85 @PathParam(Constants.USERNAME) @NotBlank String username, 86 @PathParam(Constants.SUBSCRIPTION_ID) @NotNull @PositiveOrZero Long subscriptionId 87 ) { 88 Subscription subscription = subscriptionService.getSubscription(subscriptionId, username); 89 return Response.ok(new SubscriptionIO(subscription)).build(); 90 } 91 92 @POST 93 @Tag(name = Constants.SUBSCRIPTION) 94 @Operation(description = "Create a new subscription") 95 @APIResponse( 96 description = "created", 97 responseCode = "201", 98 content = @Content(schema = @Schema(implementation = SubscriptionIO.class)), 99 links = @Link( 100 name = "unsubscribe", 101 operationId = "deleteSubscription", 102 parameters = @LinkParameter(name = Constants.SUBSCRIPTION_ID, expression = "$response.body#/id") 103 ) 104 ) 105 @APIResponse(responseCode = "400", description = "bad request") 106 @APIResponse(responseCode = "401", description = "not authorized") 107 @APIResponse(responseCode = "403", description = "forbidden") 108 @APIResponse(responseCode = "404", description = "not found") 109 @Callback( 110 name = "SubscriptionIO", 111 operations = @CallbackOperation( 112 summary = "Notify the client about an event", 113 method = "post", 114 responses = @APIResponse(responseCode = "200", description = "Notification received"), 115 requestBody = @RequestBody( 116 description = "Notification about an event", 117 content = @Content(schema = @Schema(implementation = EventIO.class)), 118 required = true 119 ) 120 ), 121 callbackUrlExpression = "{$request.body#/callbackUrl}" 122 ) 123 @Parameter(name = Constants.USERNAME) 124 public Response createSubscription( 125 @PathParam(Constants.USERNAME) @NotBlank String username, 126 @RequestBody( 127 required = true, 128 content = @Content(schema = @Schema(implementation = SubscriptionIO.class)) 129 ) @Valid SubscriptionIO subscription 130 ) { 131 Subscription created = subscriptionService.createSubscription(subscription, username); 132 return Response.status(Status.CREATED).entity(new SubscriptionIO(created)).build(); 133 } 134 135 @DELETE 136 @Path("/{" + Constants.SUBSCRIPTION_ID + "}") 137 @Tag(name = Constants.SUBSCRIPTION) 138 @Operation(description = "Delete subscription") 139 @APIResponse(description = "deleted", responseCode = "204") 140 @APIResponse(responseCode = "400", description = "bad request") 141 @APIResponse(responseCode = "401", description = "not authorized") 142 @APIResponse(responseCode = "403", description = "forbidden") 143 @APIResponse(responseCode = "404", description = "not found") 144 @Parameter(name = Constants.USERNAME) 145 @Parameter(name = Constants.SUBSCRIPTION_ID) 146 public Response deleteSubscription( 147 @PathParam(Constants.USERNAME) @NotBlank String username, 148 @PathParam(Constants.SUBSCRIPTION_ID) @NotNull @PositiveOrZero Long subscriptionId 149 ) { 150 subscriptionService.deleteSubscription(subscriptionId, username); 151 return Response.status(Status.NO_CONTENT).build(); 152 } 153 }