All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.gematik.bbriccs.fhir.codec.FhirCodec Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2024 gematik GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.gematik.bbriccs.fhir.codec;

import static java.text.MessageFormat.format;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.LenientErrorHandler;
import de.gematik.bbriccs.fhir.EncodingType;
import de.gematik.bbriccs.fhir.codec.exceptions.FhirCodecException;
import de.gematik.bbriccs.fhir.coding.ProfileStructureDefinition;
import de.gematik.bbriccs.fhir.coding.version.ProfileVersion;
import de.gematik.bbriccs.fhir.validation.*;
import de.gematik.refv.SupportedValidationModule;
import java.util.LinkedList;
import java.util.List;
import javax.annotation.Nullable;
import lombok.experimental.Delegate;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Resource;

public class FhirCodec {

  private final FhirContext ctx;
  private IParser xmlParser;
  private IParser jsonParser;

  @Delegate private final ValidatorFhir validator;

  protected FhirCodec(FhirContext ctx, ValidatorFhir validator) {
    this.ctx = ctx;
    this.validator = validator;
  }

  public String encode(IBaseResource resource, EncodingType encoding) {
    return this.encode(resource, encoding, false);
  }

  public String encode(IBaseResource resource, EncodingType encoding, boolean prettyPrint) {
    if (resource instanceof EmptyResource) {
      return "";
    }
    val parser = encoding.chooseAppropriateParser(this::getXmlParser, this::getJsonParser);
    parser.setPrettyPrint(prettyPrint);
    return parser.encodeResourceToString(resource);
  }

  public  T decode(Class expectedClass, String content) {
    val encoding = EncodingType.guessFromContent(content);
    return this.decode(expectedClass, content, encoding);
  }

  @SuppressWarnings("unchecked")
  public synchronized  T decode(
      Class expectedClass, String content, EncodingType encoding) {
    if (StringUtils.isBlank(content)) {
      // if the content is empty, there is no need to bother HAPI and just simply return an
      // EmptyResource
      return (T) new EmptyResource();
    }
    val parser = encoding.chooseAppropriateParser(this::getXmlParser, this::getJsonParser);

    try {
      return parser.parseResource(expectedClass, content);
    } catch (Throwable t) {
      throw new FhirCodecException(
          format(
              "Error while decoding content of length {0} as {1}", content.length(), expectedClass),
          t);
    }
  }

  public Resource decode(String content) {
    val encoding = EncodingType.guessFromContent(content);
    return this.decode(content, encoding);
  }

  /**
   * This method will decode the content to base resource without returning the concrete type of the
   * resource. Whenever the expected type of the concrete resource is known, it is recommended to
   * use the decode-variant with type expectation
   *
   * @param content to be decoded to a FHIR-Resource
   * @param encoding type of content
   * @return decoded base FHIR-Resource
   */
  public Resource decode(final String content, EncodingType encoding) {
    return this.decode(null, content, encoding);
  }

  private IParser getXmlParser() {
    if (this.xmlParser == null) {
      this.xmlParser = ctx.newXmlParser();
    }
    return this.xmlParser;
  }

  private IParser getJsonParser() {
    if (this.jsonParser == null) {
      this.jsonParser = ctx.newJsonParser();
    }
    return this.jsonParser;
  }

  public static FhirCodecBuilder forR4() {
    return new FhirCodecBuilder(FhirContext.forR4());
  }

  public static class FhirCodecBuilder {

    private final FhirContext ctx;
    private final List> typeHints;

    private FhirCodecBuilder(FhirContext ctx) {
      this.ctx = ctx;
      this.typeHints = new LinkedList<>();
    }

    public FhirCodecBuilder disableErrors() {
      val errorHandler = new LenientErrorHandler();
      errorHandler.disableAllErrors();
      ctx.setParserErrorHandler(errorHandler);

      return this;
    }

    public  FhirCodecBuilder withTypeHint(
        ProfileStructureDefinition definition, Class mappingClass) {
      return withTypeHint(ResourceTypeHint.forStructure(definition, mappingClass));
    }

    public  FhirCodecBuilder withTypeHint(
        ProfileStructureDefinition definition, @Nullable T version, Class mappingClass) {
      return withTypeHint(ResourceTypeHint.forStructure(definition, version, mappingClass));
    }

    public  FhirCodecBuilder withTypeHint(
        ResourceTypeHint typeHint) {
      this.typeHints.add(typeHint);
      return this;
    }

    public >
        FhirCodecBuilder withTypeHints(List typeHints) {
      this.typeHints.addAll(typeHints);
      return this;
    }

    public FhirCodec andNonProfiledValidator() {
      val validator = new NonProfiledValidator(this.ctx);
      return andCustomValidator(validator);
    }

    public FhirCodec andDummyValidator() {
      val validator = new DummyValidator(this.ctx);
      return andCustomValidator(validator);
    }

    public FhirCodec andBbriccsValidator() {
      val validator = ValidatorFhirFactory.createValidator(this.ctx);
      return andCustomValidator(validator);
    }

    public FhirCodec andReferenzValidator(SupportedValidationModule svm) {
      val validator = ReferenzValidator.withValidationModule(this.ctx, svm);
      return andCustomValidator(validator);
    }

    public FhirCodec andCustomValidator(ValidatorFhir validator) {
      this.typeHints.forEach(th -> th.register(this.ctx));
      return new FhirCodec(this.ctx, validator);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy