001/*-
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2023 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.util;
021
022import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
023import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
024import ca.uhn.fhir.context.FhirContext;
025import ca.uhn.fhir.context.FhirVersionEnum;
026import ca.uhn.fhir.context.RuntimeResourceDefinition;
027import org.hl7.fhir.instance.model.api.IBase;
028import org.hl7.fhir.instance.model.api.IBaseBinary;
029import org.hl7.fhir.instance.model.api.IBaseReference;
030import org.hl7.fhir.instance.model.api.IPrimitiveType;
031
032import java.util.List;
033
034public class BinaryUtil {
035
036        private BinaryUtil() {
037                // non instantiable
038        }
039
040        /**
041         * Fetches the base64Binary value of Binary.data (or Binary.content on versions of
042         * FHIR before R4), creating it if it does not already exist.
043         */
044        @SuppressWarnings("unchecked")
045        public static IPrimitiveType<byte[]> getOrCreateData(FhirContext theContext, IBaseBinary theBinary) {
046                String elementName = "content";
047                if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
048                        elementName = "data";
049                }
050
051                BaseRuntimeChildDefinition entryChild = AttachmentUtil.getChild(theContext, theBinary, elementName);
052                List<IBase> entries = entryChild.getAccessor().getValues(theBinary);
053                return entries
054                        .stream()
055                        .map(t -> (IPrimitiveType<byte[]>) t)
056                        .findFirst()
057                        .orElseGet(() -> {
058                                IPrimitiveType<byte[]> binary = AttachmentUtil.newPrimitive(theContext, "base64Binary", null);
059                                entryChild.getMutator().setValue(theBinary, binary);
060                                return binary;
061                        });
062        }
063
064
065        public static IBaseReference getSecurityContext(FhirContext theCtx, IBaseBinary theBinary) {
066                RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
067                BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
068                IBaseReference retVal = null;
069                if (child != null) {
070                        List<IBase> values = child.getAccessor().getValues(theBinary);
071                        if (values.size() > 0) {
072                                retVal = (IBaseReference) values.get(0);
073                        }
074                }
075                return retVal;
076        }
077
078        public static IBaseBinary newBinary(FhirContext theCtx) {
079                return (IBaseBinary) theCtx.getResourceDefinition("Binary").newInstance();
080        }
081
082        public static void setSecurityContext(FhirContext theCtx, IBaseBinary theBinary, String theSecurityContext) {
083                RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
084                BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
085
086                BaseRuntimeElementDefinition<?> referenceDef = theCtx.getElementDefinition("reference");
087                IBaseReference reference = (IBaseReference) referenceDef.newInstance();
088                child.getMutator().addValue(theBinary, reference);
089
090                reference.setReference(theSecurityContext);
091        }
092
093        public static void setData(FhirContext theCtx, IBaseBinary theBinary, byte[] theBytes, String theContentType) {
094                getOrCreateData(theCtx, theBinary).setValue(theBytes);
095
096                String elementName = "contentType";
097                BaseRuntimeChildDefinition entryChild = AttachmentUtil.getChild(theCtx, theBinary, elementName);
098                List<IBase> entries = entryChild.getAccessor().getValues(theBinary);
099                IPrimitiveType<String> contentTypeElement = entries
100                        .stream()
101                        .map(t -> (IPrimitiveType<String>) t)
102                        .findFirst()
103                        .orElseGet(() -> {
104                                IPrimitiveType<String> stringType = AttachmentUtil.newPrimitive(theCtx, "code", null);
105                                entryChild.getMutator().setValue(theBinary, stringType);
106                                return stringType;
107                        });
108                contentTypeElement.setValue(theContentType);
109
110        }
111}