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