package nl.knaw.huygens.alexandria.client; import static nl.knaw.huygens.alexandria.api.ApiConstants.HEADER_AUTH; import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.function.Function; import java.util.function.Supplier; import javax.net.ssl.SSLContext; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.SyncInvoker; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.io.FileUtils; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.glassfish.jersey.apache.connector.ApacheClientProperties; import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; import nl.knaw.huygens.alexandria.api.EndpointPaths; import nl.knaw.huygens.alexandria.api.model.AboutEntity; import nl.knaw.huygens.alexandria.api.model.AlexandriaState; import nl.knaw.huygens.alexandria.api.model.Annotator; import nl.knaw.huygens.alexandria.api.model.AnnotatorList; import nl.knaw.huygens.alexandria.api.model.CommandResponse; import nl.knaw.huygens.alexandria.api.model.CommandStatus; import nl.knaw.huygens.alexandria.api.model.StatePrototype; import nl.knaw.huygens.alexandria.api.model.search.AlexandriaQuery; import nl.knaw.huygens.alexandria.api.model.search.SearchResultPage; import nl.knaw.huygens.alexandria.api.model.text.TextAnnotationImportStatus; import nl.knaw.huygens.alexandria.api.model.text.TextEntity; import nl.knaw.huygens.alexandria.api.model.text.TextImportStatus; import nl.knaw.huygens.alexandria.api.model.text.TextRangeAnnotation; import nl.knaw.huygens.alexandria.api.model.text.TextRangeAnnotationInfo; import nl.knaw.huygens.alexandria.api.model.text.TextRangeAnnotationList; import nl.knaw.huygens.alexandria.api.model.text.view.TextViewDefinition; import nl.knaw.huygens.alexandria.api.model.text.view.TextViewList; import nl.knaw.huygens.alexandria.client.model.AnnotationList; import nl.knaw.huygens.alexandria.client.model.AnnotationPojo; import nl.knaw.huygens.alexandria.client.model.AnnotationPrototype; import nl.knaw.huygens.alexandria.client.model.ResourcePojo; import nl.knaw.huygens.alexandria.client.model.ResourcePrototype; import nl.knaw.huygens.alexandria.client.model.SubResourceList; import nl.knaw.huygens.alexandria.client.model.SubResourcePojo; import nl.knaw.huygens.alexandria.client.model.SubResourcePrototype; /* * #%L * alexandria-java-client * ======= * Copyright (C) 2015 - 2017 Huygens ING (KNAW) * ======= * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ public class AlexandriaClient implements AutoCloseable { public static final Map<String,String> NO_VIEW_PARAMETERS = Collections.emptyMap(); private WebTarget rootTarget; private String authHeader = ""; private final Client client; private final URI alexandriaURI; private boolean autoConfirm = true; public AlexandriaClient(final URI alexandriaURI) { this(alexandriaURI, null); } public AlexandriaClient(final URI alexandriaURI, SSLContext sslContext) { this.alexandriaURI = alexandriaURI; final ObjectMapper objectMapper = new ObjectMapper()// .registerModule(new Jdk8Module())// .registerModule(new JavaTimeModule()); final JacksonJaxbJsonProvider jacksonProvider = new JacksonJaxbJsonProvider(); jacksonProvider.setMapper(objectMapper); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(50); cm.setDefaultMaxPerRoute(50); ApacheConnectorProvider connectorProvider = new ApacheConnectorProvider(); ClientConfig clientConfig = new ClientConfig(jacksonProvider)// .connectorProvider(connectorProvider)// .property(ApacheClientProperties.CONNECTION_MANAGER, cm)// .property(ClientProperties.CONNECT_TIMEOUT, 60000)// .property(ClientProperties.READ_TIMEOUT, 60000); if (sslContext == null) { if ("https".equals(alexandriaURI.getScheme())) { throw new RuntimeException("SSL connections need an SSLContext, use: new AlexandriaClient(uri, sslContext) instead."); } client = ClientBuilder.newClient(clientConfig); } else { client = ClientBuilder.newBuilder()// .sslContext(sslContext)// .withConfig(clientConfig)// .build(); } rootTarget = client.target(alexandriaURI); } @Override public void close() { client.close(); } public void register(Object component) { client.register(component); rootTarget = client.target(alexandriaURI); } public void setProperty(final String jerseyClientProperty, final Object value) { client.property(jerseyClientProperty, value); rootTarget = client.target(alexandriaURI); } public void setAuthKey(final String authKey) { authHeader = "SimpleAuth " + authKey; } /** * When autoConfirm is true (default), a resource/annotation made with POST will be automatically confirmed. * * @param autoConfirm */ public void setAutoConfirm(final boolean autoConfirm) { this.autoConfirm = autoConfirm; } // Alexandria API methods public RestResult<AboutEntity> getAbout() { WebTarget path = rootTarget// .path(EndpointPaths.ABOUT); Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<AboutEntity> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toAboutEntityRestResult)// .getResult(); } public RestResult<Void> setResource(final UUID resourceId, final ResourcePrototype resource) { final WebTarget path = resourceTarget(resourceId); final Entity<ResourcePrototype> entity = Entity.json(resource); final Supplier<Response> responseSupplier = authorizedPut(path, entity); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.CREATED, voidRestResult())// .onStatus(Status.ACCEPTED, voidRestResult())// .onStatus(Status.NO_CONTENT, voidRestResult())// .getResult(); } public RestResult<UUID> addResource(final ResourcePrototype resource) { final WebTarget path = rootTarget.path(EndpointPaths.RESOURCES); final Entity<ResourcePrototype> entity = Entity.json(resource); final Supplier<Response> responseSupplier = authorizedPost(path, entity); final RestRequester<UUID> requester = RestRequester.withResponseSupplier(responseSupplier); final RestResult<UUID> addResult = requester// .onStatus(Status.CREATED, this::uuidFromLocationHeader)// .getResult(); if (autoConfirm && !addResult.hasFailed()) { confirmResource(addResult.get()); } return addResult; } public RestResult<UUID> addSubResource(final UUID parentResourceId, final SubResourcePrototype subresource) { final Entity<SubResourcePrototype> entity = Entity.json(subresource); final WebTarget path = resourceTarget(parentResourceId)// .path(EndpointPaths.SUBRESOURCES); final Supplier<Response> responseSupplier = authorizedPost(path, entity); final RestRequester<UUID> requester = RestRequester.withResponseSupplier(responseSupplier); final RestResult<UUID> addResult = requester// .onStatus(Status.CREATED, this::uuidFromLocationHeader)// .getResult(); if (autoConfirm && !addResult.hasFailed()) { confirmResource(addResult.get()); } return addResult; } public RestResult<Void> setSubResource(final UUID parentResourceId, final UUID subResourceId, final SubResourcePrototype subresource) { final Entity<SubResourcePrototype> entity = Entity.json(subresource); final WebTarget path = resourceTarget(parentResourceId)// .path(EndpointPaths.SUBRESOURCES)// .path(subResourceId.toString()); final Supplier<Response> responseSupplier = authorizedPut(path, entity); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.CREATED, voidRestResult())// .onStatus(Status.NO_CONTENT, voidRestResult())// .getResult(); } public RestResult<ResourcePojo> getResource(final UUID uuid) { WebTarget path = resourceTarget(uuid); Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<ResourcePojo> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toResourcePojoRestResult)// .getResult(); } public RestResult<SubResourcePojo> getSubResource(final UUID uuid) { WebTarget path = resourceTarget(uuid); Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<SubResourcePojo> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toSubResourcePojoRestResult)// .getResult(); } public RestResult<AnnotationList> getResourceAnnotations(final UUID resourceUUID) { WebTarget path = resourceTarget(resourceUUID).path(EndpointPaths.ANNOTATIONS); final RestRequester<AnnotationList> requester = RestRequester.withResponseSupplier(anonymousGet(path)); return requester// .onStatus(Status.OK, this::toAnnotationListRestResult)// .getResult(); } public RestResult<SubResourceList> getSubResources(final UUID resourceUUID) { WebTarget path = resourceTarget(resourceUUID).path(EndpointPaths.SUBRESOURCES); final RestRequester<SubResourceList> requester = RestRequester.withResponseSupplier(anonymousGet(path)); return requester// .onStatus(Status.OK, this::toSubResourceListRestResult)// .getResult(); } public RestResult<Void> confirmResource(final UUID resourceUUID) { return confirm(EndpointPaths.RESOURCES, resourceUUID); } public RestResult<Void> confirmAnnotation(final UUID annotationUuid) { return confirm(EndpointPaths.ANNOTATIONS, annotationUuid); } public RestResult<Void> setAnnotator(UUID resourceUUID, String code, Annotator annotator) { final Entity<Annotator> entity = Entity.json(annotator); final WebTarget path = annotatorsTarget(resourceUUID, code); final Supplier<Response> responseSupplier = authorizedPut(path, entity); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.CREATED, voidRestResult())// .onStatus(Status.NO_CONTENT, voidRestResult())// .getResult(); } public RestResult<Annotator> getAnnotator(UUID resourceUUID, String code) { final WebTarget path = annotatorsTarget(resourceUUID, code); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<Annotator> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toAnnotatorRestResult)// .getResult(); } public RestResult<AnnotatorList> getAnnotators(UUID resourceUUID) { final WebTarget path = resourceTarget(resourceUUID)// .path(EndpointPaths.ANNOTATORS); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<AnnotatorList> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toAnnotatorListRestResult)// .getResult(); } public RestResult<Void> setResourceText(final UUID resourceUUID, final File file) throws IOException { return setResourceText(resourceUUID, FileUtils.readFileToString(file, StandardCharsets.UTF_8)); } public RestResult<Void> setResourceText(final UUID resourceUUID, final String xml) { final Entity<String> entity = Entity.entity(xml, MediaType.TEXT_XML); WebTarget path = resourceTextTarget(resourceUUID); final Supplier<Response> responseSupplier = authorizedPut(path, entity); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.ACCEPTED, voidRestResult())// .getResult(); } public RestResult<TextImportStatus> getTextImportStatus(final UUID resourceUUID) { final WebTarget path = resourceTextTarget(resourceUUID)// .path("status"); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<TextImportStatus> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toTextImportStatusRestResult)// .getResult(); } public RestResult<TextEntity> getTextInfo(UUID resourceUUID) { WebTarget path = resourceTextTarget(resourceUUID); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<TextEntity> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toTextEntityRestResult)// .getResult(); } public RestResult<String> getTextAsString(final UUID uuid) { WebTarget path = resourceTextTarget(uuid).path("xml"); return stringResult(path); } public RestResult<String> getTextAsString(final UUID uuid, final String viewName) { WebTarget path = resourceTextTarget(uuid).path("xml").queryParam("view", viewName); return stringResult(path); } public RestResult<String> getTextAsString(final UUID uuid, final String viewName, final Map<String, String> viewParameters) { WebTarget path = resourceTextTarget(uuid).path("xml").queryParam("view", viewName); path = addViewParameters(viewParameters, path); return stringResult(path); } public RestResult<String> getTextAsDot(final UUID uuid) { WebTarget path = resourceTextTarget(uuid).path("dot"); return stringResult(path); } public RestResult<Void> addResourceTextRangeAnnotations(UUID resourceUUID, TextRangeAnnotationList textAnnotations) { final Entity<TextRangeAnnotationList> entity = Entity.json(textAnnotations); WebTarget path = resourceTextTarget(resourceUUID)// .path(EndpointPaths.ANNOTATIONBATCH); final Supplier<Response> responseSupplier = authorizedPost(path, entity); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.ACCEPTED, voidRestResult())// .getResult(); } public RestResult<TextAnnotationImportStatus> getResourceTextRangeAnnotationBatchImportStatus(final UUID resourceUUID) { final WebTarget path = resourceTextTarget(resourceUUID)// .path(EndpointPaths.ANNOTATIONBATCH)// .path("status"); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<TextAnnotationImportStatus> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toTextAnnotationImportStatusRestResult)// .getResult(); } public RestResult<TextRangeAnnotationInfo> setResourceTextRangeAnnotation(UUID resourceUUID, TextRangeAnnotation textAnnotation) { final Entity<TextRangeAnnotation> entity = Entity.json(textAnnotation); WebTarget path = resourceTextTarget(resourceUUID)// .path(EndpointPaths.ANNOTATIONS)// .path(textAnnotation.getId().toString()); final Supplier<Response> responseSupplier = authorizedPut(path, entity); final RestRequester<TextRangeAnnotationInfo> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.CREATED, this::toTextRangeAnnotationInfoRestResult)// .onStatus(Status.NO_CONTENT, this::toTextRangeAnnotationInfoRestResult)// .getResult(); } public RestResult<TextRangeAnnotation> getResourceTextRangeAnnotation(UUID resourceUUID, UUID annotationUUID) { WebTarget path = resourceTextTarget(resourceUUID)// .path(EndpointPaths.ANNOTATIONS)// .path(annotationUUID.toString()); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<TextRangeAnnotation> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toTextRangeAnnotationRestResult)// .getResult(); } public RestResult<TextRangeAnnotationList> getResourceTextRangeAnnotations(UUID resourceUUID) { WebTarget path = resourceTextTarget(resourceUUID)// .path(EndpointPaths.ANNOTATIONS); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<TextRangeAnnotationList> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toTextRangeAnnotationListRestResult)// .getResult(); } public RestResult<Void> setResourceTextView(final UUID resourceUUID, final String textViewName, final TextViewDefinition textView) { final Entity<TextViewDefinition> entity = Entity.json(textView); final WebTarget path = resourceTextTarget(resourceUUID)// .path(EndpointPaths.TEXTVIEWS)// .path(textViewName); final Supplier<Response> responseSupplier = authorizedPut(path, entity); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.CREATED, voidRestResult())// .onStatus(Status.NO_CONTENT, voidRestResult())// .getResult(); } public RestResult<TextViewDefinition> getResourceTextView(final UUID uuid, final String textViewName) { return getResourceTextView(uuid, textViewName, NO_VIEW_PARAMETERS); } public RestResult<TextViewDefinition> getResourceTextView(final UUID uuid, final String textViewName, final Map<String, String> viewParameters) { WebTarget path = resourceTextTarget(uuid).path(EndpointPaths.TEXTVIEWS).path(textViewName); path = addViewParameters(viewParameters, path); Supplier<Response> anonymousGet = anonymousGet(path); final RestRequester<TextViewDefinition> requester = RestRequester.withResponseSupplier(anonymousGet); return requester// .onStatus(Status.OK, this::toTextViewDefinitionRestResult)// .getResult(); } private WebTarget addViewParameters(final Map<String, String> viewParameters, WebTarget path) { Set<Map.Entry<String, String>> entries = viewParameters.entrySet(); for (Map.Entry<String, String> entry : entries) { String k = entry.getKey(); String v = entry.getValue(); path = path.queryParam("view." + k, v); } return path; } public RestResult<TextViewList> getResourceTextViews(final UUID uuid) { WebTarget path = resourceTextTarget(uuid).path(EndpointPaths.TEXTVIEWS); Supplier<Response> anonymousGet = anonymousGet(path); final RestRequester<TextViewList> requester = RestRequester.withResponseSupplier(anonymousGet); return requester// .onStatus(Status.OK, this::toTextViewListRestResult)// .getResult(); } public RestResult<UUID> annotateResource(final UUID resourceUUID, final AnnotationPrototype annotationPrototype) { return annotate(resourceUUID, annotationPrototype, EndpointPaths.RESOURCES); } public RestResult<UUID> annotateAnnotation(final UUID annotationUuid, final AnnotationPrototype annotationPrototype) { return annotate(annotationUuid, annotationPrototype, EndpointPaths.ANNOTATIONS); } public RestResult<AnnotationPojo> getAnnotation(final UUID uuid) { WebTarget path = annotationTarget(uuid); return getAnnotationRestResult(path); } public RestResult<AnnotationPojo> getAnnotationRevision(final UUID uuid, final Integer revision) { WebTarget path = annotationTarget(uuid).path(EndpointPaths.REV).path(revision.toString()); return getAnnotationRestResult(path); } public RestResult<AnnotationList> getAnnotationAnnotations(final UUID annotationUUID) { WebTarget path = annotationTarget(annotationUUID).path(EndpointPaths.ANNOTATIONS); final RestRequester<AnnotationList> requester = RestRequester.withResponseSupplier(anonymousGet(path)); return requester// .onStatus(Status.OK, this::toAnnotationListRestResult)// .getResult(); } public RestResult<UUID> addSearch(AlexandriaQuery query) { final Entity<AlexandriaQuery> entity = Entity.json(query); final WebTarget path = rootTarget.path(EndpointPaths.SEARCHES); final Supplier<Response> responseSupplier = authorizedPost(path, entity); final RestRequester<UUID> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.CREATED, this::uuidFromLocationHeader)// .getResult(); } public RestResult<SearchResultPage> getSearchResultPage(UUID searchId) { return getSearchResultPage(searchId, 1); } public RestResult<SearchResultPage> getSearchResultPage(UUID searchId, Integer page) { final WebTarget path = rootTarget// .path(EndpointPaths.SEARCHES)// .path(searchId.toString())// .path(EndpointPaths.RESULTPAGES)// .path(page.toString()); final RestRequester<SearchResultPage> requester = RestRequester.withResponseSupplier(anonymousGet(path)); return requester// .onStatus(Status.OK, this::toSearchResultPageRestResult)// .getResult(); } public RestResult<CommandResponse> doCommand(String commandName, Map<String, Object> parameters) { final Entity<Map<String, Object>> entity = Entity.json(parameters); final WebTarget path = rootTarget.path(EndpointPaths.COMMANDS).path(commandName); final Supplier<Response> responseSupplier = authorizedPost(path, entity); final RestRequester<CommandResponse> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toCommandResponseRestResult)// .onStatus(Status.ACCEPTED, this::extractCommandStatusId)// .getResult(); } public RestResult<CommandStatus> getCommandStatus(final String commandName, final UUID resourceUUID) { final WebTarget path = rootTarget.path(EndpointPaths.COMMANDS)// .path(commandName)// .path(resourceUUID.toString())// .path("status"); final Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<CommandStatus> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toCommandStatusRestResult)// .getResult(); } public RestResult<Void> deprecateAnnotation(UUID uuid) { WebTarget path = annotationTarget(uuid); final RestRequester<Void> requester = RestRequester.withResponseSupplier(authorizedDelete(path)); return requester// .onStatus(Status.NO_CONTENT, voidRestResult())// .getResult(); } // private methods private RestResult<UUID> annotate(final UUID annotatableUuid, final AnnotationPrototype annotationPrototype, final String annotatablePath) { final Entity<AnnotationPrototype> entity = Entity.json(annotationPrototype); final WebTarget path = rootTarget// .path(annotatablePath)// .path(annotatableUuid.toString())// .path(EndpointPaths.ANNOTATIONS); final Supplier<Response> responseSupplier = authorizedPost(path, entity); final RestRequester<UUID> requester = RestRequester.withResponseSupplier(responseSupplier); final RestResult<UUID> annotateResult = requester// .onStatus(Status.CREATED, this::uuidFromLocationHeader)// .getResult(); if (autoConfirm && !annotateResult.hasFailed()) { confirmAnnotation(annotateResult.get()); } return annotateResult; } private WebTarget resourceTextTarget(final UUID resourceUUID) { return resourceTarget(resourceUUID).path(EndpointPaths.TEXT); } private WebTarget resourceTarget(final UUID uuid) { return rootTarget// .path(EndpointPaths.RESOURCES)// .path(uuid.toString()); } private RestResult<Void> confirm(final String endpoint, final UUID resourceUUID) { final StatePrototype state = new StatePrototype().setState(AlexandriaState.CONFIRMED); final Entity<StatePrototype> confirmation = Entity.json(state); final WebTarget path = rootTarget// .path(endpoint)// .path(resourceUUID.toString())// .path("state"); final Supplier<Response> responseSupplier = authorizedPut(path, confirmation); final RestRequester<Void> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.NO_CONTENT, voidRestResult())// .getResult(); } private RestResult<String> toStringRestResult(final Response response) { return toEntityRestResult(response, String.class); } private RestResult<AboutEntity> toAboutEntityRestResult(final Response response) { return toEntityRestResult(response, AboutEntity.class); } private RestResult<ResourcePojo> toResourcePojoRestResult(final Response response) { return toEntityRestResult(response, ResourcePojo.class); } private RestResult<SubResourcePojo> toSubResourcePojoRestResult(final Response response) { return toEntityRestResult(response, SubResourcePojo.class); } private RestResult<Annotator> toAnnotatorRestResult(final Response response) { return toEntityRestResult(response, Annotator.class); } private RestResult<AnnotatorList> toAnnotatorListRestResult(final Response response) { return toEntityRestResult(response, AnnotatorList.class); } private RestResult<AnnotationPojo> toAnnotationPojoRestResult(final Response response) { return toEntityRestResult(response, AnnotationPojo.class); } private RestResult<TextImportStatus> toTextImportStatusRestResult(final Response response) { return toEntityRestResult(response, TextImportStatus.class); } private RestResult<TextAnnotationImportStatus> toTextAnnotationImportStatusRestResult(final Response response) { return toEntityRestResult(response, TextAnnotationImportStatus.class); } private RestResult<CommandStatus> toCommandStatusRestResult(final Response response) { return toEntityRestResult(response, CommandStatus.class); } private RestResult<TextEntity> toTextEntityRestResult(final Response response) { return toEntityRestResult(response, TextEntity.class); } private RestResult<TextViewDefinition> toTextViewDefinitionRestResult(final Response response) { return toEntityRestResult(response, TextViewDefinition.class); } private RestResult<TextViewList> toTextViewListRestResult(final Response response) { return toEntityRestResult(response, TextViewList.class); } private RestResult<SearchResultPage> toSearchResultPageRestResult(final Response response) { return toEntityRestResult(response, SearchResultPage.class); } private RestResult<CommandResponse> toCommandResponseRestResult(final Response response) { return toEntityRestResult(response, CommandResponse.class); } private RestResult<TextRangeAnnotation> toTextRangeAnnotationRestResult(final Response response) { return toEntityRestResult(response, TextRangeAnnotation.class); } private RestResult<TextRangeAnnotationList> toTextRangeAnnotationListRestResult(final Response response) { return toEntityRestResult(response, TextRangeAnnotationList.class); } private RestResult<TextRangeAnnotationInfo> toTextRangeAnnotationInfoRestResult(final Response response) { return toEntityRestResult(response, TextRangeAnnotationInfo.class); } private RestResult<AnnotationList> toAnnotationListRestResult(Response response) { return toEntityRestResult(response, AnnotationList.class); } private RestResult<SubResourceList> toSubResourceListRestResult(Response response) { return toEntityRestResult(response, SubResourceList.class); } private <E> RestResult<E> toEntityRestResult(final Response response, final Class<E> entityClass) { final RestResult<E> result = new RestResult<>(); final E cargo = response.readEntity(entityClass); result.setCargo(cargo); return result; } private RestResult<CommandResponse> extractCommandStatusId(final Response response) { final String location = response.getHeaderString("Location"); String[] parts = location.split("/"); UUID statusId = UUID.fromString(parts[parts.length - 2]); CommandResponse commandResponse = new CommandResponse(); commandResponse.setStatusId(statusId); final RestResult<CommandResponse> result = new RestResult<>(); return result.setCargo(commandResponse); } private RestResult<URI> uriFromLocationHeader(final Response response) { final RestResult<URI> result = new RestResult<>(); final String location = response.getHeaderString("Location"); final URI uri = URI.create(location); result.setCargo(uri); return result; } private RestResult<UUID> uuidFromLocationHeader(final Response response) { final RestResult<UUID> result = new RestResult<>(); final String location = response.getHeaderString("Location"); final UUID uuid = UUID.fromString(location.replaceFirst(".*/", "")); result.setCargo(uuid); return result; } private Supplier<Response> anonymousGet(final WebTarget target) { return () -> target.request().get(); } private Supplier<Response> authorizedPut(final WebTarget path, final Entity<?> entity) { return () -> authorizedRequest(path).put(entity); } private Supplier<Response> authorizedPost(final WebTarget path, final Entity<?> entity) { return () -> authorizedRequest(path).post(entity); } private Supplier<Response> authorizedDelete(final WebTarget path) { return () -> authorizedRequest(path).delete(); } private SyncInvoker authorizedRequest(final WebTarget target) { return target.request()// .accept(MediaType.APPLICATION_JSON_TYPE)// .header(HEADER_AUTH, authHeader); } private RestResult<String> stringResult(WebTarget path) { Supplier<Response> responseSupplier = anonymousGet(path); final RestRequester<String> requester = RestRequester.withResponseSupplier(responseSupplier); return requester// .onStatus(Status.OK, this::toStringRestResult)// .getResult(); } private WebTarget annotationTarget(final UUID uuid) { return rootTarget.path(EndpointPaths.ANNOTATIONS).path(uuid.toString()); } private RestResult<AnnotationPojo> getAnnotationRestResult(WebTarget path) { final RestRequester<AnnotationPojo> requester = RestRequester.withResponseSupplier(anonymousGet(path)); return requester// .onStatus(Status.OK, this::toAnnotationPojoRestResult)// .getResult(); } private WebTarget annotatorsTarget(UUID resourceUUID, String code) { return resourceTarget(resourceUUID)// .path(EndpointPaths.ANNOTATORS)// .path(code); } private Function<Response, RestResult<Void>> voidRestResult() { return (response) -> { response.bufferEntity(); // to notify connectors, such as the ApacheConnector, that the entity has been "consumed" and that it should release the current connection back into the Apache // ConnectionManager pool (if being used). https://java.net/jira/browse/JERSEY-3149 return new RestResult<>(); }; } public WebTarget getRootTarget() { return rootTarget; } }