Class AnnotationSetsWebService

java.lang.Object
ubic.gemma.rest.AnnotationSetsWebService

@Service @Path("/") public class AnnotationSetsWebService extends Object
REST surface for the unified AnnotationSet entity.

Two URL families:

  • Per-datasetPOST /datasets/{id}/annotation-sets, GET /datasets/{id}/annotation-sets, GET /datasets/{id}/annotation-sets/draft, PUT /datasets/{id}/annotation-sets/draft. JAX-RS annotations are declared on DatasetsWebService because Jersey resolves /datasets/* against the class-level @Path("/datasets") and never falls through to this resource's class-level @Path("/"). The handler bodies live here; the DatasetsWebService methods delegate.
  • Cross-datasetGET /annotation-sets, GET /annotation-sets/{id}, POST /annotation-sets/{id}/finalize, POST /annotation-sets/{id}/reopen, DELETE /annotation-sets/{id}. Declared here directly.

Idempotency on create is (investigation, role, runId). The service-level attach carries the audit-conditional aspect so an event row is emitted only on actual insert, not on retry.

  • Constructor Details

    • AnnotationSetsWebService

      public AnnotationSetsWebService()
  • Method Details

    • getCandidates

      @GET @Path("/candidates") @PreAuthorize("hasAuthority('GROUP_CURATOR')") public jakarta.ws.rs.core.Response getCandidates(@Context jakarta.ws.rs.core.UriInfo uriInfo)
      Screening queue: redirect to the existing /datasets?filter=curationDetails.needsAttention=true query. Implemented as a 302 so any query parameters the caller supplies (limit, offset, sort, etc.) pass through verbatim.
    • submitAnnotationSet

      public jakarta.ws.rs.core.Response submitAnnotationSet(DatasetArg<?> datasetArg, @Nullable AnnotationSetsWebService.AnnotationSetRequest body)
      Create or upsert an annotation set on a dataset. The body's role determines the lifecycle shape: PROPOSAL requires a runId; DRAFT derives one from the current user (use the dedicated draft PUT instead for upsert semantics); SNAPSHOT generates a UUID when runId is omitted.
    • listAnnotationSets

      public jakarta.ws.rs.core.Response listAnnotationSets(DatasetArg<?> datasetArg, @Nullable String role, @Nullable String source, @Nullable String createdBy, @Nullable String shape)
      List annotation sets attached to a dataset, newest first. Filter by role, source, createdBy; choose response shape with shape=full|meta (default full).
    • getDraftForDataset

      public jakarta.ws.rs.core.Response getDraftForDataset(DatasetArg<?> datasetArg, @Nullable String onBehalfOf)
      Fetch a curator's DRAFT for the given dataset. 404 if no draft exists. Convenience over the role-filtered list because the curation client hits this on every dataset open.
      Parameters:
      onBehalfOf - whose draft to read; see resolveCurator(String). Reading is delegated for the same reason writing is — an agent fetching "the draft" without saying whose would get its own.
    • upsertDraftForDataset

      public jakarta.ws.rs.core.Response upsertDraftForDataset(DatasetArg<?> datasetArg, @Nullable String onBehalfOf, @Nullable AnnotationSetsWebService.UpsertDraftRequest body)
      Upsert a curator's DRAFT for the given dataset. One DRAFT per (dataset, curator); body's payloadJson + optional parkedElements + optional parentId (the PROPOSAL the draft was seeded from). Returns 201 on create, 200 on update.
      Parameters:
      onBehalfOf - which curator this draft belongs to; see resolveCurator(String)
    • listAnnotationSetsAcross

      @GET @Path("/annotation-sets") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public PaginatedResponseDataObject<AnnotationSetsWebService.AnnotationSetSummaryResponse> listAnnotationSetsAcross(@QueryParam("role") @Nullable String role, @QueryParam("source") @Nullable String source, @QueryParam("createdBy") @Nullable String createdBy, @QueryParam("kind") @Nullable String kind, @QueryParam("status") @Nullable String status, @QueryParam("datasetIds") @Nullable String datasetIds, @QueryParam("offset") @DefaultValue("0") OffsetArg offsetArg, @QueryParam("limit") @DefaultValue("20") LimitArg limitArg, @QueryParam("sort") @DefaultValue("-createdAt") String sort)
      Cross-experiment list of annotation sets, paginated. Thin metadata projection (no payloadJson).
    • getAnnotationSet

      @GET @Path("/annotation-sets/{id}") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public ResponseDataObject<AnnotationSetsWebService.AnnotationSetResponse> getAnnotationSet(@PathParam("id") Long id)
      Single annotation set (full payload).
    • finalizeAnnotationSet

      @POST @Path("/annotation-sets/{id}/finalize") @Consumes("application/json") @Produces("application/json") @PreAuthorize("isAuthenticated()") public jakarta.ws.rs.core.Response finalizeAnnotationSet(@PathParam("id") Long id, @QueryParam("onBehalfOf") @Nullable String onBehalfOf, @Nullable AnnotationSetsWebService.FinalizeRequest body)
      Mark an annotation set finalized. For DRAFT this means "done editing"; for SNAPSHOT this is the curator's bless to mark the row as the polished canonical view. Idempotent: second call returns 200 with no state change.
    • setAnnotationSetStatus

      @PATCH @Path("/annotation-sets/{id}/status") @Consumes("application/json") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public jakarta.ws.rs.core.Response setAnnotationSetStatus(@PathParam("id") Long id, @Nullable AnnotationSetsWebService.StatusRequest body)
      Set where a proposal stands with its reviewer.
    • triageAnnotationSet

      @PATCH @Path("/annotation-sets/{id}/triage") @Consumes("application/json") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public jakarta.ws.rs.core.Response triageAnnotationSet(@PathParam("id") Long id, @QueryParam("onBehalfOf") @Nullable String onBehalfOf, @Nullable AnnotationSetsWebService.TriageRequest body)
      Record or replace the caller's triage ruling on an annotation set.

      Idempotent per judge: a second call from the same judge updates their standing ruling rather than adding one, so a curator changing their mind leaves one row and not a history.

    • withdrawTriage

      @DELETE @Path("/annotation-sets/{id}/triage") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public jakarta.ws.rs.core.Response withdrawTriage(@PathParam("id") Long id, @QueryParam("onBehalfOf") @Nullable String onBehalfOf)
      Withdraw the caller's ruling, returning the set to un-triaged if it was the only one. 204 whether or not a row was there -- a withdrawal that finds nothing has still achieved what it asked for.
    • getTriage

      @GET @Path("/annotation-sets/{id}/triage") @Produces("application/json") @PreAuthorize("isAuthenticated()") public jakarta.ws.rs.core.Response getTriage(@PathParam("id") Long id)
      Every ruling on an annotation set, most recent first. The head of the list is the effective verdict.
    • ruleOnFinding

      @POST @Path("/annotation-sets/{id}/dispositions") @Consumes("application/json") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public jakarta.ws.rs.core.Response ruleOnFinding(@PathParam("id") Long id, @QueryParam("onBehalfOf") @Nullable String onBehalfOf, @Nullable AnnotationSetsWebService.DispositionRequest body)
      Record a curator's ruling on ONE finding inside an audit set.

      Append-only: a curator who changes their mind adds a row rather than replacing one, and the read folds to the newest per finding.

    • getDispositions

      @GET @Path("/annotation-sets/{id}/dispositions") @Produces("application/json") @PreAuthorize("isAuthenticated()") public jakarta.ws.rs.core.Response getDispositions(@PathParam("id") Long id, @QueryParam("history") @DefaultValue("false") boolean history)
      The rulings on an annotation set's findings — the standing one per finding, or the whole sequence.
    • clearDispositions

      @DELETE @Path("/annotation-sets/{id}/dispositions") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR')") public jakarta.ws.rs.core.Response clearDispositions(@PathParam("id") Long id)
      Erase every per-finding ruling on an annotation set so it can be dispositioned again from scratch.
    • reopenAnnotationSet

      @POST @Path("/annotation-sets/{id}/reopen") @Consumes("application/json") @Produces("application/json") @PreAuthorize("isAuthenticated()") public jakarta.ws.rs.core.Response reopenAnnotationSet(@PathParam("id") Long id)
      Clear finalized status on an annotation set. Idempotent.
    • updateAnnotationSetProvenance

      @PATCH @Path("/annotation-sets/{id}") @Consumes("application/json") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN') or hasAuthority('GROUP_AGENT')") public jakarta.ws.rs.core.Response updateAnnotationSetProvenance(@PathParam("id") Long id, @Nullable AnnotationSetsWebService.ProvenanceRequest body)
    • deleteAnnotationSet

      @DELETE @Path("/annotation-sets/{id}") @Produces("application/json") @PreAuthorize("hasAuthority('GROUP_CURATOR') or hasAuthority('GROUP_ADMIN')") public jakarta.ws.rs.core.Response deleteAnnotationSet(@PathParam("id") Long id)
      Delete an annotation set by id. Descendants survive with their parent cleared via FK ON DELETE SET NULL.