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