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.rest.api;
021
022import ca.uhn.fhir.util.CoverageIgnore;
023import org.apache.commons.lang3.Validate;
024import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
025import org.hl7.fhir.instance.model.api.IBaseResource;
026import org.hl7.fhir.instance.model.api.IIdType;
027
028import java.util.ArrayList;
029import java.util.Collection;
030import java.util.HashMap;
031import java.util.List;
032import java.util.Map;
033import java.util.Optional;
034
035public class MethodOutcome {
036
037        private Boolean myCreated;
038        private IIdType myId;
039        private IBaseOperationOutcome myOperationOutcome;
040        private IBaseResource myResource;
041        private Map<String, List<String>> myResponseHeaders;
042        private Collection<Runnable> myResourceViewCallbacks;
043        private Integer myResponseStatusCode;
044
045        /**
046         * Constructor
047         */
048        public MethodOutcome() {
049                super();
050        }
051
052        /**
053         * Constructor
054         *
055         * @param theId      The ID of the created/updated resource
056         * @param theCreated If not null, indicates whether the resource was created (as opposed to being updated). This is generally not needed, since the server can assume based on the method being called
057         *                   whether the result was a creation or an update. However, it can be useful if you are implementing an update method that does a create if the ID doesn't already exist.
058         */
059        @CoverageIgnore
060        public MethodOutcome(IIdType theId, Boolean theCreated) {
061                myId = theId;
062                myCreated = theCreated;
063        }
064
065        /**
066         * Constructor
067         *
068         * @param theId                   The ID of the created/updated resource
069         * @param theBaseOperationOutcome The operation outcome to return with the response (or null for none)
070         */
071        public MethodOutcome(IIdType theId, IBaseOperationOutcome theBaseOperationOutcome) {
072                myId = theId;
073                myOperationOutcome = theBaseOperationOutcome;
074        }
075
076        /**
077         * Constructor
078         *
079         * @param theId                   The ID of the created/updated resource
080         * @param theBaseOperationOutcome The operation outcome to return with the response (or null for none)
081         * @param theCreated              If not null, indicates whether the resource was created (as opposed to being updated). This is generally not needed, since the server can assume based on the method being called
082         *                                whether the result was a creation or an update. However, it can be useful if you are implementing an update method that does a create if the ID doesn't already exist.
083         */
084        public MethodOutcome(IIdType theId, IBaseOperationOutcome theBaseOperationOutcome, Boolean theCreated) {
085                myId = theId;
086                myOperationOutcome = theBaseOperationOutcome;
087                myCreated = theCreated;
088        }
089
090        /**
091         * Constructor
092         *
093         * @param theId The ID of the created/updated resource
094         */
095        public MethodOutcome(IIdType theId) {
096                myId = theId;
097        }
098
099        /**
100         * Constructor
101         *
102         * @param theOperationOutcome The operation outcome resource to return
103         */
104        public MethodOutcome(IBaseOperationOutcome theOperationOutcome) {
105                myOperationOutcome = theOperationOutcome;
106        }
107
108        /**
109         * This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are
110         * returned to client instances, if the server has responded with an HTTP 201 Created.
111         */
112        public Boolean getCreated() {
113                return myCreated;
114        }
115
116        /**
117         * If not null, indicates whether the resource was created (as opposed to being updated). This is generally not needed, since the server can assume based on the method being called whether the
118         * result was a creation or an update. However, it can be useful if you are implementing an update method that does a create if the ID doesn't already exist.
119         * <p>
120         * Users of HAPI should only interact with this method in Server applications
121         * </p>
122         *
123         * @param theCreated If not null, indicates whether the resource was created (as opposed to being updated). This is generally not needed, since the server can assume based on the method being called
124         *                   whether the result was a creation or an update. However, it can be useful if you are implementing an update method that does a create if the ID doesn't already exist.
125         * @return Returns a reference to <code>this</code> for easy method chaining
126         */
127        public MethodOutcome setCreated(Boolean theCreated) {
128                myCreated = theCreated;
129                return this;
130        }
131
132        public IIdType getId() {
133                return myId;
134        }
135
136        /**
137         * @param theId The ID of the created/updated resource
138         * @return Returns a reference to <code>this</code> for easy method chaining
139         */
140        public MethodOutcome setId(IIdType theId) {
141                myId = theId;
142                return this;
143        }
144
145        /**
146         * Returns the {@link IBaseOperationOutcome} resource to return to the client or <code>null</code> if none.
147         *
148         * @return This method <b>will return null</b>, unlike many methods in the API.
149         */
150        public IBaseOperationOutcome getOperationOutcome() {
151                return myOperationOutcome;
152        }
153
154        /**
155         * Sets the {@link IBaseOperationOutcome} resource to return to the client. Set to <code>null</code> (which is the default) if none.
156         *
157         * @return Returns a reference to <code>this</code> for easy method chaining
158         */
159        public MethodOutcome setOperationOutcome(IBaseOperationOutcome theBaseOperationOutcome) {
160                myOperationOutcome = theBaseOperationOutcome;
161                return this;
162        }
163
164        /**
165         * <b>From a client response:</b> If the method returned an actual resource body (e.g. a create/update with
166         * "Prefer: return=representation") this field will be populated with the
167         * resource itself.
168         */
169        public IBaseResource getResource() {
170                return myResource;
171        }
172
173        /**
174         * <b>In a server response</b>: This field may be populated in server code with the final resource for operations
175         * where a resource body is being created/updated. E.g. for an update method, this field could be populated with
176         * the resource after the update is applied, with the new version ID, lastUpdate time, etc.
177         * <p>
178         * This field is optional, but if it is populated the server will return the resource body if requested to
179         * do so via the HTTP Prefer header.
180         * </p>
181         *
182         * @return Returns a reference to <code>this</code> for easy method chaining
183         * @see #registerResourceViewCallback(Runnable) to register a callback that should be invoked by the framework before the resource is shown/returned to a client
184         */
185        public MethodOutcome setResource(IBaseResource theResource) {
186                myResource = theResource;
187                return this;
188        }
189
190        /**
191         * Gets the headers for the HTTP response
192         */
193        public Map<String, List<String>> getResponseHeaders() {
194                if (myResponseHeaders == null) {
195                        myResponseHeaders = new HashMap<>();
196                }
197                return myResponseHeaders;
198        }
199
200        /**
201         * Sets the headers for the HTTP response
202         */
203        public void setResponseHeaders(Map<String, List<String>> theResponseHeaders) {
204                myResponseHeaders = theResponseHeaders;
205        }
206
207        public Optional<String> getFirstResponseHeader(String theHeader) {
208                List<String> values = getResponseHeaders().get(theHeader);
209
210                if (values == null || values.isEmpty()) {
211                        return Optional.empty();
212                } else {
213                        return Optional.of(values.get(0));
214                }
215        }
216
217        /**
218         * Registers a callback to be invoked before the resource in this object gets
219         * returned to the client. Note that this is an experimental API and may change.
220         *
221         * @param theCallback The callback
222         * @since 4.0.0
223         */
224        public void registerResourceViewCallback(Runnable theCallback) {
225                Validate.notNull(theCallback, "theCallback must not be null");
226
227                if (myResourceViewCallbacks == null) {
228                        myResourceViewCallbacks = new ArrayList<>(2);
229                }
230                myResourceViewCallbacks.add(theCallback);
231        }
232
233        /**
234         * Fires callbacks registered to {@link #registerResourceViewCallback(Runnable)} and then
235         * clears the list of registered callbacks.
236         *
237         * @since 4.0.0
238         */
239        public void fireResourceViewCallbacks() {
240                if (myResourceViewCallbacks != null) {
241                        myResourceViewCallbacks.forEach(t -> t.run());
242                        myResourceViewCallbacks.clear();
243                }
244        }
245
246        public void setCreatedUsingStatusCode(int theResponseStatusCode) {
247                if (theResponseStatusCode == Constants.STATUS_HTTP_201_CREATED) {
248                        setCreated(true);
249                }
250        }
251
252        protected boolean hasResource() {
253                return myResource != null;
254        }
255
256        public void setResponseStatusCode(int theResponseStatusCode) {
257                myResponseStatusCode = theResponseStatusCode;
258        }
259
260        public int getResponseStatusCode() {
261                return isResponseStatusCodeSet() ? myResponseStatusCode : 0;
262        }
263
264        public boolean isResponseStatusCodeSet() {
265                return myResponseStatusCode != null;
266        }
267}