001package org.hl7.fhir.convertors.txClient;
002
003import java.io.IOException;
004import java.net.URISyntaxException;
005import java.util.EnumSet;
006import java.util.HashMap;
007import java.util.Map;
008
009import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
010import org.hl7.fhir.exceptions.FHIRException;
011import org.hl7.fhir.r4.model.Resource;
012import org.hl7.fhir.r4.utils.client.EFhirClientException;
013import org.hl7.fhir.r4.utils.client.FHIRToolingClient;
014import org.hl7.fhir.r5.formats.IParser.OutputStyle;
015import org.hl7.fhir.r5.formats.JsonParser;
016import org.hl7.fhir.r5.model.Bundle;
017import org.hl7.fhir.r5.model.CanonicalResource;
018import org.hl7.fhir.r5.model.CapabilityStatement;
019import org.hl7.fhir.r5.model.OperationOutcome;
020import org.hl7.fhir.r5.model.Parameters;
021import org.hl7.fhir.r5.model.TerminologyCapabilities;
022import org.hl7.fhir.r5.model.ValueSet;
023import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
024import org.hl7.fhir.r5.terminologies.client.ITerminologyClient;
025import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ITerminologyClientFactory;
026import org.hl7.fhir.r5.utils.client.network.ClientHeaders;
027import org.hl7.fhir.utilities.FhirPublication;
028import org.hl7.fhir.utilities.ToolingClientLogger;
029import org.hl7.fhir.utilities.Utilities;
030import org.hl7.fhir.utilities.http.HTTPHeader;
031
032public class TerminologyClientR4 implements ITerminologyClient {
033
034
035  public static class TerminologyClientR4Factory implements ITerminologyClientFactory {
036
037    @Override
038    public ITerminologyClient makeClient(String id, String url, String userAgent, ToolingClientLogger logger) throws URISyntaxException {
039      return new TerminologyClientR4(id, checkEndsWith("/r4", url), userAgent);
040    }
041
042    private String checkEndsWith(String term, String url) {
043      if (url.endsWith(term))
044        return url;
045      if (Utilities.isTxFhirOrgServer(url)) {
046        return Utilities.pathURL(url, term);
047      }
048      return url;
049    }
050
051    @Override
052    public String getVersion() {
053      return "4.0.1";
054    }
055  }
056  
057  private final FHIRToolingClient client; 
058  private ClientHeaders clientHeaders;
059  private String id;
060  private ITerminologyConversionLogger logger;
061
062  public TerminologyClientR4(String id, String address, String userAgent) throws URISyntaxException {
063    this.client = new FHIRToolingClient(address, userAgent);
064    setClientHeaders(new ClientHeaders());
065    this.id = id;
066  }
067
068  public TerminologyClientR4(String id, String address, String userAgent, ClientHeaders clientHeaders) throws URISyntaxException {
069    this.client = new FHIRToolingClient(address, userAgent);
070    setClientHeaders(clientHeaders);
071    this.id = id;
072  }
073
074  @Override
075  public String getId() {
076    return id;
077  }
078
079
080
081  public EnumSet<FhirPublication> supportableVersions() {
082    // todo
083    return EnumSet.range(FhirPublication.STU3, FhirPublication.R5);
084  }
085  
086  public void setAllowedVersions(EnumSet<FhirPublication> versions) {
087    // todo
088  }
089  
090  public EnumSet<FhirPublication> getAllowedVersions() {
091    return null; // todo
092  }
093  
094  public FhirPublication getActualVersion() {
095    return FhirPublication.R4;
096  }
097  
098  
099  @Override
100  public TerminologyCapabilities getTerminologyCapabilities() throws FHIRException {
101    return (TerminologyCapabilities) convertResource("getTerminologyCapabilities.response", client.getTerminologyCapabilities());
102  }
103
104  @Override
105  public String getAddress() {
106    return client.getAddress();
107  }
108
109  @Override
110  public ValueSet expandValueset(ValueSet vs, Parameters p) throws FHIRException {
111    org.hl7.fhir.r4.model.ValueSet vs2 = vs == null ? null : (org.hl7.fhir.r4.model.ValueSet) convertResource("expandValueset.valueset", vs);
112    org.hl7.fhir.r4.model.Parameters p2 = p == null ? null :  (org.hl7.fhir.r4.model.Parameters) convertResource("expandValueset.parameters", p);
113    try {
114      vs2 = client.expandValueset(vs2, p2); // todo: second parameter
115      return (ValueSet) convertResource("expandValueset.response", vs2);
116    } catch (org.hl7.fhir.r4.utils.client.EFhirClientException e) {
117      if (e.getServerErrors().size() > 0) {
118        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), (org.hl7.fhir.r5.model.OperationOutcome) convertResource("expandValueset.error", e.getServerErrors().get(0)));
119      } else {
120        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage());        
121      }
122    }
123  }
124
125
126  @Override
127  public Parameters validateCS(Parameters pin) throws FHIRException {
128    try {
129      org.hl7.fhir.r4.model.Parameters p2 = (org.hl7.fhir.r4.model.Parameters) convertResource("validateCS.request", pin);
130      p2 = client.operateType(org.hl7.fhir.r4.model.CodeSystem.class, "validate-code", p2);
131      return (Parameters) convertResource("validateCS.response", p2);
132    } catch (EFhirClientException e) {
133      if (e.getServerErrors().size() == 1) {
134        OperationOutcome op =  (OperationOutcome) convertResource("validateCS.error", e.getServerErrors().get(0));
135        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), op, e);
136      } else {
137        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), e);        
138      }
139    } catch (IOException e) {
140      throw new FHIRException(e);
141    }
142  }
143
144  @Override
145  public Parameters batchValidateCS(Parameters pin) throws FHIRException {
146    try {
147      org.hl7.fhir.r4.model.Parameters p2 = (org.hl7.fhir.r4.model.Parameters) convertResource("validateCS.request", pin);
148      p2 = client.operateType(org.hl7.fhir.r4.model.CodeSystem.class, "batch-validate-code", p2);
149      return (Parameters) convertResource("validateCS.response", p2);
150    } catch (EFhirClientException e) {
151      if (e.getServerErrors().size() == 1) {
152        OperationOutcome op =  (OperationOutcome) convertResource("validateCS.error", e.getServerErrors().get(0));
153        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), op, e);
154      } else {
155        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), e);
156      }
157    } catch (IOException e) {
158      throw new FHIRException(e);
159    }
160  }
161
162
163
164  @Override
165  public Parameters subsumes(Parameters pin) throws FHIRException {
166    try {
167      org.hl7.fhir.r4.model.Parameters p2 = (org.hl7.fhir.r4.model.Parameters) convertResource("subsumes.request", pin);
168      p2 = client.operateType(org.hl7.fhir.r4.model.CodeSystem.class, "subsumes", p2);
169      return (Parameters) convertResource("subsumes.response", p2);
170    } catch (EFhirClientException e) {
171      if (e.getServerErrors().size() == 1) {
172        OperationOutcome op =  (OperationOutcome) convertResource("subsumes.error", e.getServerErrors().get(0));
173        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), op, e);
174      } else {
175        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), e);        
176      }
177    } catch (IOException e) {
178      throw new FHIRException(e);
179    }
180  }
181
182  @Override
183  public Parameters validateVS(Parameters pin) throws FHIRException {
184    try {
185      org.hl7.fhir.r4.model.Parameters p2 = (org.hl7.fhir.r4.model.Parameters) convertResource("validateVS.request", pin);
186      p2 = client.operateType(org.hl7.fhir.r4.model.ValueSet.class, "validate-code", p2);
187      return (Parameters) convertResource("validateVS.response", p2);
188    } catch (EFhirClientException e) {
189      if (e.getServerErrors().size() == 1) {
190        OperationOutcome op =  (OperationOutcome) convertResource("validateVS.error", e.getServerErrors().get(0));
191        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), op, e);
192      } else {
193        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), e);        
194      }
195    } catch (IOException e) {
196      throw new FHIRException(e);
197    }
198  }
199
200  @Override
201  public Parameters batchValidateVS(Parameters pin) throws FHIRException {
202    try {
203      org.hl7.fhir.r4.model.Parameters p2 = (org.hl7.fhir.r4.model.Parameters) convertResource("validateVS.request", pin);
204      p2 = client.operateType(org.hl7.fhir.r4.model.ValueSet.class, "batch-validate-code", p2);
205      return (Parameters) convertResource("validateVS.response", p2);
206    } catch (EFhirClientException e) {
207      if (e.getServerErrors().size() == 1) {
208        OperationOutcome op =  (OperationOutcome) convertResource("validateVS.error", e.getServerErrors().get(0));
209        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), op, e);
210      } else {
211        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), e);
212      }
213    } catch (IOException e) {
214      throw new FHIRException(e);
215    }
216  }
217
218  @Override
219  public ITerminologyClient setTimeoutFactor(int i) {
220    client.setTimeoutFactor(i);
221    return this;
222  }
223
224  @Override
225  public ToolingClientLogger getLogger() {
226    return client.getLogger();
227  }
228
229  @Override
230  public ITerminologyClient setLogger(ToolingClientLogger txLog) {
231    client.setLogger(txLog);
232    return this;
233  }
234
235  @Override
236  public ITerminologyClient setRetryCount(int retryCount) throws FHIRException {
237    client.setRetryCount(retryCount);
238    return this;
239  }
240
241  @Override
242  public CapabilityStatement getCapabilitiesStatementQuick() throws FHIRException {
243    return (CapabilityStatement) convertResource("getCapabilitiesStatementQuick.response", client.getCapabilitiesStatementQuick());
244  }
245
246  @Override
247  public CapabilityStatement getCapabilitiesStatement() throws FHIRException {
248    return (CapabilityStatement) convertResource("getCapabilitiesStatement.response", client.getCapabilitiesStatement());
249  }
250
251  @Override
252  public Parameters lookupCode(Map<String, String> params) throws FHIRException {
253    return (Parameters) convertResource("lookupCode.response", client.lookupCode(params));
254  }
255
256  @Override
257  public Parameters lookupCode(Parameters params) throws FHIRException {
258    return (Parameters) convertResource("lookupCode.response", client.lookupCode((org.hl7.fhir.r4.model.Parameters) convertResource("lookupCode.request", params)));
259  }
260
261  @Override
262  public int getRetryCount() throws FHIRException {
263    return client.getRetryCount();
264  }
265
266  @Override
267  public Bundle batch(Bundle batch) {
268    org.hl7.fhir.r4.model.Bundle result = client.transaction((org.hl7.fhir.r4.model.Bundle) convertResource("validateBatch.request", batch));
269    return result == null ? null : (Bundle) convertResource("validateBatch.response", result);
270  }
271
272  @Override
273  public CanonicalResource read(String type, String id) {
274    Class<Resource> t;
275    try {
276      t = (Class<Resource>) Class.forName("org.hl7.fhir.r4.model." + type);// todo: do we have to deal with any resource renaming? Use cases are limited...
277    } catch (ClassNotFoundException e) {
278      throw new FHIRException("Unable to fetch resources of type " + type + " in R2");
279    }
280    org.hl7.fhir.r4.model.Resource r4 = client.read(t, id);
281    if (r4 == null) {
282      throw new FHIRException("Unable to fetch resource " + Utilities.pathURL(getAddress(), type, id));
283    }
284    org.hl7.fhir.r5.model.Resource r5 = convertResource("read.result", r4);
285    if (r5 == null) {
286      throw new FHIRException("Unable to convert resource " + Utilities.pathURL(getAddress(), type, id) + " to R5 (internal representation)");
287    }
288    if (!(r5 instanceof CanonicalResource)) {
289      throw new FHIRException("Unable to convert resource " + Utilities.pathURL(getAddress(), type, id) + " to R5 canonical resource (internal representation)");
290    }
291    return (CanonicalResource) r5;
292  }
293
294  @Override
295  public Iterable<HTTPHeader> getClientHeaders() {
296    return clientHeaders.headers();
297  }
298
299  @Override
300  public ITerminologyClient setClientHeaders(ClientHeaders clientHeaders) {
301    this.clientHeaders = clientHeaders;
302    if (this.clientHeaders != null) {
303      this.client.setClientHeaders(this.clientHeaders.headers());
304    }
305    this.client.setVersionInMimeTypes(true);
306    return this;
307  }
308
309  @Override
310  public ITerminologyClient setUserAgent(String userAgent) {
311    client.setUserAgent(userAgent);
312    return this;
313  }
314
315  @Override
316  public String getUserAgent() {
317    return client.getUserAgent();
318  }
319
320  @Override
321  public String getServerVersion() {
322    return client.getServerVersion();
323  }
324
325
326  @Override
327  public ITerminologyClient setAcceptLanguage(String lang) {
328    client.setAcceptLanguage(lang);
329    return this;
330  }
331  
332  @Override
333  public ITerminologyClient setContentLanguage(String lang) {
334    client.setContentLanguage(lang);
335    return this;
336  }
337  
338  @Override
339  public int getUseCount() {
340    return client.getUseCount();
341  }
342
343  @Override
344  public Bundle search(String type, String criteria) {    
345    org.hl7.fhir.r4.model.Bundle result = client.search(type, criteria);
346    return result == null ? null : (Bundle) convertResource("search.result", result);
347  }
348
349  @Override
350  public Parameters translate(Parameters params) throws FHIRException {  
351    return (Parameters) convertResource("translate.response", client.translate((org.hl7.fhir.r4.model.Parameters) convertResource("translate.request", params)));
352  }
353
354  private org.hl7.fhir.r4.model.Resource convertResource(String name, org.hl7.fhir.r5.model.Resource resource) {
355    if (logger != null) {
356      try {
357        logger.log(name, resource.fhirType(), "r5", new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).composeBytes(resource));
358      } catch (IOException e) {
359        throw new FHIRException(e);
360      }
361    }
362    org.hl7.fhir.r4.model.Resource res = VersionConvertorFactory_40_50.convertResource(resource);
363    if (logger != null) {
364      try {
365        logger.log(name, resource.fhirType(), "r4", new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(org.hl7.fhir.r4.formats.IParser.OutputStyle.PRETTY).composeBytes(res));
366      } catch (IOException e) {
367        throw new FHIRException(e);
368      }
369    }
370    return res;
371  }
372
373  private org.hl7.fhir.r5.model.Resource convertResource(String name, org.hl7.fhir.r4.model.Resource resource) {
374    if (logger != null && name != null) {
375      try {
376        logger.log(name, resource.fhirType(), "r4", new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(org.hl7.fhir.r4.formats.IParser.OutputStyle.PRETTY).composeBytes(resource));
377      } catch (IOException e) {
378        throw new FHIRException(e);
379      }
380    }
381    org.hl7.fhir.r5.model.Resource res = VersionConvertorFactory_40_50.convertResource(resource);
382    if (logger != null && name != null) {
383      try {
384        logger.log(name, resource.fhirType(), "r5", new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).composeBytes(res));
385      } catch (IOException e) {
386        throw new FHIRException(e);
387      }
388    }
389    return res;
390  }
391
392  @Override
393  public void setConversionLogger(ITerminologyConversionLogger logger) {
394    this.logger = logger;    
395  }
396
397  @Override
398  public OperationOutcome validateResource(org.hl7.fhir.r5.model.Resource res) {
399    try {
400      org.hl7.fhir.r4.model.Resource r2 = convertResource("validate.request", res);
401      Resource p2 = client.validate(r2, null);
402      return (OperationOutcome) convertResource("validateVS.response", p2);
403    } catch (EFhirClientException e) {
404      if (e.getServerErrors().size() == 1) {
405        OperationOutcome op =  (OperationOutcome) convertResource("validateVS.error", e.getServerErrors().get(0));
406        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), op, e);
407      } else {
408        throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getCode(), e.getMessage(), e);        
409      }
410    }
411  }
412  
413}