001package org.hl7.fhir.r4.utils.client.network;
002
003import okhttp3.Headers;
004import okhttp3.MediaType;
005import okhttp3.Request;
006import okhttp3.RequestBody;
007import org.hl7.fhir.r4.model.Bundle;
008import org.hl7.fhir.r4.model.Resource;
009import org.hl7.fhir.r4.utils.client.EFhirClientException;
010import org.hl7.fhir.utilities.ToolingClientLogger;
011
012import java.io.IOException;
013import java.net.URI;
014import java.util.Map;
015import java.util.concurrent.TimeUnit;
016
017public class Client {
018
019  public static final String DEFAULT_CHARSET = "UTF-8";
020  private static final long DEFAULT_TIMEOUT = 5000;
021  private ToolingClientLogger logger;
022  private FhirLoggingInterceptor fhirLoggingInterceptor;
023  private int retryCount;
024  private long timeout = DEFAULT_TIMEOUT;
025
026  public ToolingClientLogger getLogger() {
027    return logger;
028  }
029
030  public void setLogger(ToolingClientLogger logger) {
031    this.logger = logger;
032    this.fhirLoggingInterceptor = new FhirLoggingInterceptor(logger);
033  }
034
035  public int getRetryCount() {
036    return retryCount;
037  }
038
039  public void setRetryCount(int retryCount) {
040    this.retryCount = retryCount;
041  }
042
043  public long getTimeout() {
044    return timeout;
045  }
046
047  public void setTimeout(long timeout) {
048    this.timeout = timeout;
049  }
050
051  public <T extends Resource> ResourceRequest<T> issueOptionsRequest(URI optionsUri,
052                                                                     String resourceFormat,
053                                                                     String message,
054                                                                     long timeout) throws IOException {
055    Request.Builder request = new Request.Builder()
056      .method("OPTIONS", null)
057      .url(optionsUri.toURL());
058
059    return executeFhirRequest(request, resourceFormat, new Headers.Builder().build(), message, retryCount, timeout);
060  }
061
062  public <T extends Resource> ResourceRequest<T> issueGetResourceRequest(URI resourceUri,
063                                                                         String resourceFormat,
064                                                                         Headers headers,
065                                                                         String message,
066                                                                         long timeout) throws IOException {
067    Request.Builder request = new Request.Builder()
068      .url(resourceUri.toURL());
069
070    return executeFhirRequest(request, resourceFormat, headers, message, retryCount, timeout);
071  }
072
073  public int tester(int trytry) {
074    return 5;
075  }
076  public <T extends Resource> ResourceRequest<T> issuePutRequest(URI resourceUri,
077                                                                 byte[] payload,
078                                                                 String resourceFormat,
079                                                                 String message,
080                                                                 long timeout) throws IOException {
081    return issuePutRequest(resourceUri, payload, resourceFormat, new Headers.Builder().build(), message, timeout);
082  }
083
084  public <T extends Resource> ResourceRequest<T> issuePutRequest(URI resourceUri,
085                                                                 byte[] payload,
086                                                                 String resourceFormat,
087                                                                 Headers headers,
088                                                                 String message,
089                                                                 long timeout) throws IOException {
090    if (payload == null) throw new EFhirClientException("PUT requests require a non-null payload");
091    RequestBody body = RequestBody.create(payload);
092    Request.Builder request = new Request.Builder()
093      .url(resourceUri.toURL())
094      .put(body);
095
096    return executeFhirRequest(request, resourceFormat, headers, message, retryCount, timeout);
097  }
098
099  public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri,
100                                                                  byte[] payload,
101                                                                  String resourceFormat,
102                                                                  String message,
103                                                                  long timeout) throws IOException {
104    return issuePostRequest(resourceUri, payload, resourceFormat, new Headers.Builder().build(), message, timeout);
105  }
106
107  public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri,
108                                                                  byte[] payload,
109                                                                  String resourceFormat,
110                                                                  Headers headers,
111                                                                  String message,
112                                                                  long timeout) throws IOException {
113    if (payload == null) throw new EFhirClientException("POST requests require a non-null payload");
114    RequestBody body = RequestBody.create(MediaType.parse(resourceFormat + ";charset=" + DEFAULT_CHARSET), payload);
115    Request.Builder request = new Request.Builder()
116      .url(resourceUri.toURL())
117      .post(body);
118
119    return executeFhirRequest(request, resourceFormat, headers, message, retryCount, timeout);
120  }
121
122  public boolean issueDeleteRequest(URI resourceUri) throws IOException {
123    Request.Builder request = new Request.Builder()
124      .url(resourceUri.toURL())
125      .delete();
126    return executeFhirRequest(request, null, new Headers.Builder().build(), null, retryCount, timeout).isSuccessfulRequest();
127  }
128
129  public Bundle issueGetFeedRequest(URI resourceUri, String resourceFormat) throws IOException {
130    Request.Builder request = new Request.Builder()
131      .url(resourceUri.toURL());
132
133    return executeBundleRequest(request, resourceFormat, new Headers.Builder().build(), null, retryCount, timeout);
134  }
135
136  public Bundle issuePostFeedRequest(URI resourceUri,
137                                     Map<String, String> parameters,
138                                     String resourceName,
139                                     Resource resource,
140                                     String resourceFormat) throws IOException {
141    String boundary = "----WebKitFormBoundarykbMUo6H8QaUnYtRy";
142    byte[] payload = ByteUtils.encodeFormSubmission(parameters, resourceName, resource, boundary);
143    RequestBody body = RequestBody.create(MediaType.parse(resourceFormat + ";charset=" + DEFAULT_CHARSET), payload);
144    Request.Builder request = new Request.Builder()
145      .url(resourceUri.toURL())
146      .post(body);
147
148    return executeBundleRequest(request, resourceFormat, new Headers.Builder().build(), null, retryCount, timeout);
149  }
150
151  public Bundle postBatchRequest(URI resourceUri,
152                                 byte[] payload,
153                                 String resourceFormat,
154                                 String message,
155                                 int timeout) throws IOException {
156    if (payload == null) throw new EFhirClientException("POST requests require a non-null payload");
157    RequestBody body = RequestBody.create(MediaType.parse(resourceFormat + ";charset=" + DEFAULT_CHARSET), payload);
158    Request.Builder request = new Request.Builder()
159      .url(resourceUri.toURL())
160      .post(body);
161
162    return executeBundleRequest(request, resourceFormat, new Headers.Builder().build(), message, retryCount, timeout);
163  }
164
165  public <T extends Resource> Bundle executeBundleRequest(Request.Builder request,
166                                                             String resourceFormat,
167                                                             Headers headers,
168                                                             String message,
169                                                             int retryCount,
170                                                             long timeout) throws IOException {
171    return new FhirRequestBuilder(request)
172      .withLogger(fhirLoggingInterceptor)
173      .withResourceFormat(resourceFormat)
174      .withRetryCount(retryCount)
175      .withMessage(message)
176      .withHeaders(headers == null ? new Headers.Builder().build() : headers)
177      .withTimeout(timeout, TimeUnit.MILLISECONDS)
178      .executeAsBatch();
179  }
180
181  public <T extends Resource> ResourceRequest<T> executeFhirRequest(Request.Builder request,
182                                                                       String resourceFormat,
183                                                                       Headers headers,
184                                                                       String message,
185                                                                       int retryCount,
186                                                                       long timeout) throws IOException {
187    return new FhirRequestBuilder(request)
188      .withLogger(fhirLoggingInterceptor)
189      .withResourceFormat(resourceFormat)
190      .withRetryCount(retryCount)
191      .withMessage(message)
192      .withHeaders(headers == null ? new Headers.Builder().build() : headers)
193      .withTimeout(timeout, TimeUnit.MILLISECONDS)
194      .execute();
195  }
196}