001/*-
002 * #%L
003 * HAPI FHIR Storage api
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.jpa.binary.api;
021
022import ca.uhn.fhir.rest.api.server.RequestDetails;
023import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
024import jakarta.annotation.Nonnull;
025import org.hl7.fhir.instance.model.api.IBaseBinary;
026import org.hl7.fhir.instance.model.api.IIdType;
027
028import java.io.IOException;
029import java.io.InputStream;
030import java.io.OutputStream;
031
032public interface IBinaryStorageSvc {
033
034        /**
035         * Gets the maximum number of bytes that can be stored in a single binary
036         * file by this service. The default is {@link Long#MAX_VALUE}
037         */
038        long getMaximumBinarySize();
039
040        /**
041         * Given a blob ID, return true if it is valid for the underlying storage mechanism, false otherwise.
042         *
043         * @param theNewBlobId the blob ID to validate
044         * @return true if the blob ID is valid, false otherwise.
045         */
046        default boolean isValidBlobId(String theNewBlobId) {
047                return true; // default method here as we don't want to break existing implementations
048        }
049
050        /**
051         * Sets the maximum number of bytes that can be stored in a single binary
052         * file by this service. The default is {@link Long#MAX_VALUE}
053         *
054         * @param theMaximumBinarySize The maximum size
055         */
056        void setMaximumBinarySize(long theMaximumBinarySize);
057
058        /**
059         * Gets the minimum number of bytes that will be stored. Binary content smaller
060         * * than this threshold may be inlined even if a binary storage service
061         * * is active.
062         */
063        int getMinimumBinarySize();
064
065        /**
066         * Sets the minimum number of bytes that will be stored. Binary content smaller
067         * than this threshold may be inlined even if a binary storage service
068         * is active.
069         */
070        void setMinimumBinarySize(int theMinimumBinarySize);
071
072        /**
073         * Give the storage service the ability to veto items from storage
074         *
075         * @param theSize        How large is the item
076         * @param theResourceId  What is the resource ID it will be associated with
077         * @param theContentType What is the content type
078         * @return <code>true</code> if the storage service should store the item
079         */
080        boolean shouldStoreBlob(long theSize, IIdType theResourceId, String theContentType);
081
082        /**
083         * Generate a new blob ID that will be passed to {@link #storeBlob(IIdType, String, String, InputStream)} later
084         */
085        String newBlobId();
086
087        /**
088         * Store a new binary blob
089         *
090         * @param theResourceId   The resource ID that owns this blob. Note that it should not be possible to retrieve a blob without both the resource ID and the blob ID being correct.
091         * @param theBlobIdOrNull If set, forces
092         * @param theContentType  The content type to associate with this blob
093         * @param theInputStream  An InputStream to read from. This method should close the stream when it has been fully consumed.
094         * @return Returns details about the stored data
095         * @deprecated Use {@link #storeBlob(IIdType theResourceId, String theBlobIdOrNull, String theContentType,
096         *      InputStream theInputStream, RequestDetails theRequestDetails)} instead. This method
097         *      will be removed because it doesn't receive the 'theRequestDetails' parameter it needs to forward to the pointcut)
098         */
099        @Deprecated(since = "6.6.0", forRemoval = true)
100        @Nonnull
101        default StoredDetails storeBlob(
102                        IIdType theResourceId, String theBlobIdOrNull, String theContentType, InputStream theInputStream)
103                        throws IOException {
104                return storeBlob(theResourceId, theBlobIdOrNull, theContentType, theInputStream, new ServletRequestDetails());
105        }
106
107        /**
108         * Store a new binary blob
109         *
110         * @param theResourceId   The resource ID that owns this blob. Note that it should not be possible to retrieve a blob without both the resource ID and the blob ID being correct.
111         * @param theBlobIdOrNull If set, forces
112         * @param theContentType  The content type to associate with this blob
113         * @param theInputStream  An InputStream to read from. This method should close the stream when it has been fully consumed.
114         * @param theRequestDetails The operation request details.
115         * @return Returns details about the stored data
116         */
117        @Nonnull
118        StoredDetails storeBlob(
119                        IIdType theResourceId,
120                        String theBlobIdOrNull,
121                        String theContentType,
122                        InputStream theInputStream,
123                        RequestDetails theRequestDetails)
124                        throws IOException;
125
126        StoredDetails fetchBlobDetails(IIdType theResourceId, String theBlobId) throws IOException;
127
128        /**
129         * @return Returns <code>true</code> if the blob was found and written, of <code>false</code> if the blob was not found (i.e. it was expunged or the ID was invalid)
130         */
131        boolean writeBlob(IIdType theResourceId, String theBlobId, OutputStream theOutputStream) throws IOException;
132
133        void expungeBlob(IIdType theResourceId, String theBlobId);
134
135        /**
136         * Fetch the contents of the given blob
137         *
138         * @param theResourceId The resource ID
139         * @param theBlobId     The blob ID
140         * @return The payload as a byte array
141         */
142        byte[] fetchBlob(IIdType theResourceId, String theBlobId) throws IOException;
143
144        /**
145         * Fetch the byte[] contents of a given Binary resource's `data` element. If the data is a standard base64encoded string that is embedded, return it.
146         * Otherwise, attempt to load the externalized binary blob via the the externalized binary storage service.
147         *
148         * @param theResource The  Binary resource you want to extract data bytes from
149         * @return The binary data blob as a byte array
150         */
151        byte[] fetchDataBlobFromBinary(IBaseBinary theResource) throws IOException;
152}