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