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