001/*-
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 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.stream().map(t -> (IPrimitiveType<byte[]>) t).findFirst().orElseGet(() -> {
054                        IPrimitiveType<byte[]> binary = AttachmentUtil.newPrimitive(theContext, "base64Binary", null);
055                        entryChild.getMutator().setValue(theBinary, binary);
056                        return binary;
057                });
058        }
059
060        public static IBaseReference getSecurityContext(FhirContext theCtx, IBaseBinary theBinary) {
061                RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
062                BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
063                IBaseReference retVal = null;
064                if (child != null) {
065                        List<IBase> values = child.getAccessor().getValues(theBinary);
066                        if (values.size() > 0) {
067                                retVal = (IBaseReference) values.get(0);
068                        }
069                }
070                return retVal;
071        }
072
073        public static IBaseBinary newBinary(FhirContext theCtx) {
074                return (IBaseBinary) theCtx.getResourceDefinition("Binary").newInstance();
075        }
076
077        public static void setSecurityContext(FhirContext theCtx, IBaseBinary theBinary, String theSecurityContext) {
078                RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
079                BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
080
081                BaseRuntimeElementDefinition<?> referenceDef = theCtx.getElementDefinition("reference");
082                IBaseReference reference = (IBaseReference) referenceDef.newInstance();
083                child.getMutator().addValue(theBinary, reference);
084
085                reference.setReference(theSecurityContext);
086        }
087
088        public static void setData(FhirContext theCtx, IBaseBinary theBinary, byte[] theBytes, String theContentType) {
089                getOrCreateData(theCtx, theBinary).setValue(theBytes);
090
091                String elementName = "contentType";
092                BaseRuntimeChildDefinition entryChild = AttachmentUtil.getChild(theCtx, theBinary, elementName);
093                List<IBase> entries = entryChild.getAccessor().getValues(theBinary);
094                IPrimitiveType<String> contentTypeElement = entries.stream()
095                                .map(t -> (IPrimitiveType<String>) t)
096                                .findFirst()
097                                .orElseGet(() -> {
098                                        IPrimitiveType<String> stringType = AttachmentUtil.newPrimitive(theCtx, "code", null);
099                                        entryChild.getMutator().setValue(theBinary, stringType);
100                                        return stringType;
101                                });
102                contentTypeElement.setValue(theContentType);
103        }
104}