001/*-
002 * #%L
003 * HAPI FHIR JPA Server
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.partition;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.jpa.entity.PartitionEntity;
024import ca.uhn.fhir.model.primitive.IntegerDt;
025import ca.uhn.fhir.rest.annotation.Operation;
026import ca.uhn.fhir.rest.annotation.OperationParam;
027import ca.uhn.fhir.rest.annotation.ResourceParam;
028import ca.uhn.fhir.rest.api.server.RequestDetails;
029import ca.uhn.fhir.rest.server.provider.ProviderConstants;
030import ca.uhn.fhir.util.ParametersUtil;
031import jakarta.annotation.Nonnull;
032import org.hl7.fhir.instance.model.api.IBase;
033import org.hl7.fhir.instance.model.api.IBaseParameters;
034import org.hl7.fhir.instance.model.api.IPrimitiveType;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037import org.springframework.beans.factory.annotation.Autowired;
038
039import java.util.List;
040
041import static ca.uhn.fhir.jpa.partition.PartitionLookupSvcImpl.validatePartitionIdSupplied;
042import static org.apache.commons.lang3.StringUtils.isNotBlank;
043import static org.hl7.fhir.instance.model.api.IPrimitiveType.toValueOrNull;
044
045/**
046 * This HAPI FHIR Server Plain Provider class provides the following operations:
047 * <ul>
048 *    <li><code>partition-management-create-partition</code></li>
049 *    <li><code>partition-management-update-partition</code></li>
050 *    <li><code>partition-management-delete-partition</code></li>
051 *    <li><code>partition-management-read-partition</code></li>
052 *    <li><code>partition-management-list-partitions</code></li>
053 * </ul>
054 */
055public class PartitionManagementProvider {
056        private static final Logger ourLog = LoggerFactory.getLogger(PartitionLookupSvcImpl.class);
057
058        @Autowired
059        private FhirContext myCtx;
060
061        @Autowired
062        private IPartitionLookupSvc myPartitionLookupSvc;
063
064        /**
065         * Add Partition:
066         * <code>
067         * $partition-management-create-partition
068         * </code>
069         */
070        @Operation(name = ProviderConstants.PARTITION_MANAGEMENT_CREATE_PARTITION)
071        public IBaseParameters addPartition(
072                        @ResourceParam IBaseParameters theRequest,
073                        @OperationParam(
074                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID,
075                                                        min = 1,
076                                                        max = 1,
077                                                        typeName = "integer")
078                                        IPrimitiveType<Integer> thePartitionId,
079                        @OperationParam(
080                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME,
081                                                        min = 1,
082                                                        max = 1,
083                                                        typeName = "code")
084                                        IPrimitiveType<String> thePartitionName,
085                        @OperationParam(
086                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC,
087                                                        min = 0,
088                                                        max = 1,
089                                                        typeName = "string")
090                                        IPrimitiveType<String> thePartitionDescription,
091                        RequestDetails theRequestDetails) {
092
093                if (thePartitionId == null && thePartitionName != null && thePartitionName.hasValue()) {
094                        thePartitionId = requestRandomPartitionId(thePartitionName);
095                }
096
097                validatePartitionIdSupplied(myCtx, toValueOrNull(thePartitionId));
098
099                PartitionEntity input = parseInput(thePartitionId, thePartitionName, thePartitionDescription);
100
101                // Note: Input validation happens inside IPartitionLookupSvc
102                PartitionEntity output = myPartitionLookupSvc.createPartition(input, theRequestDetails);
103
104                IBaseParameters retVal = prepareOutput(output);
105
106                return retVal;
107        }
108
109        @Nonnull
110        private IPrimitiveType<Integer> requestRandomPartitionId(IPrimitiveType<String> thePartitionName) {
111                int unusedPartitionId = myPartitionLookupSvc.generateRandomUnusedPartitionId();
112                ourLog.info(
113                                "Request to create partition came in without a partition ID. Auto-assigning an available ID.[partition_id={}, partition_name={}]",
114                                unusedPartitionId,
115                                thePartitionName);
116                return new IntegerDt(unusedPartitionId);
117        }
118
119        /**
120         * Add Partition:
121         * <code>
122         * $partition-management-read-partition
123         * </code>
124         */
125        @Operation(name = ProviderConstants.PARTITION_MANAGEMENT_READ_PARTITION, idempotent = true)
126        public IBaseParameters addPartition(
127                        @ResourceParam IBaseParameters theRequest,
128                        @OperationParam(
129                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID,
130                                                        min = 1,
131                                                        max = 1,
132                                                        typeName = "integer")
133                                        IPrimitiveType<Integer> thePartitionId) {
134                validatePartitionIdSupplied(myCtx, toValueOrNull(thePartitionId));
135
136                // Note: Input validation happens inside IPartitionLookupSvc
137                PartitionEntity output = myPartitionLookupSvc.getPartitionById(thePartitionId.getValue());
138
139                return prepareOutput(output);
140        }
141
142        /**
143         * Add Partition:
144         * <code>
145         * $partition-management-update-partition
146         * </code>
147         */
148        @Operation(name = ProviderConstants.PARTITION_MANAGEMENT_UPDATE_PARTITION)
149        public IBaseParameters updatePartition(
150                        @ResourceParam IBaseParameters theRequest,
151                        @OperationParam(
152                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID,
153                                                        min = 1,
154                                                        max = 1,
155                                                        typeName = "integer")
156                                        IPrimitiveType<Integer> thePartitionId,
157                        @OperationParam(
158                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME,
159                                                        min = 1,
160                                                        max = 1,
161                                                        typeName = "code")
162                                        IPrimitiveType<String> thePartitionName,
163                        @OperationParam(
164                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC,
165                                                        min = 0,
166                                                        max = 1,
167                                                        typeName = "string")
168                                        IPrimitiveType<String> thePartitionDescription) {
169                validatePartitionIdSupplied(myCtx, toValueOrNull(thePartitionId));
170
171                PartitionEntity input = parseInput(thePartitionId, thePartitionName, thePartitionDescription);
172
173                // Note: Input validation happens inside IPartitionLookupSvc
174                PartitionEntity output = myPartitionLookupSvc.updatePartition(input);
175
176                IBaseParameters retVal = prepareOutput(output);
177
178                return retVal;
179        }
180
181        /**
182         * Add Partition:
183         * <code>
184         * $partition-management-delete-partition
185         * </code>
186         */
187        @Operation(name = ProviderConstants.PARTITION_MANAGEMENT_DELETE_PARTITION)
188        public IBaseParameters updatePartition(
189                        @ResourceParam IBaseParameters theRequest,
190                        @OperationParam(
191                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID,
192                                                        min = 1,
193                                                        max = 1,
194                                                        typeName = "integer")
195                                        IPrimitiveType<Integer> thePartitionId) {
196                validatePartitionIdSupplied(myCtx, toValueOrNull(thePartitionId));
197
198                myPartitionLookupSvc.deletePartition(thePartitionId.getValue());
199
200                IBaseParameters retVal = ParametersUtil.newInstance(myCtx);
201                ParametersUtil.addParameterToParametersString(myCtx, retVal, "message", "Success");
202
203                return retVal;
204        }
205
206        /**
207         * Add Partition:
208         * <code>
209         * $partition-management-list-partitions
210         * </code>
211         */
212        @Operation(name = ProviderConstants.PARTITION_MANAGEMENT_LIST_PARTITIONS, idempotent = true)
213        public IBaseParameters addPartitions(@ResourceParam IBaseParameters theRequest) {
214                List<PartitionEntity> output = myPartitionLookupSvc.listPartitions();
215                return prepareOutputList(output);
216        }
217
218        private IBaseParameters prepareOutput(PartitionEntity theOutput) {
219                IBaseParameters retVal = ParametersUtil.newInstance(myCtx);
220                ParametersUtil.addParameterToParametersInteger(
221                                myCtx, retVal, ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, theOutput.getId());
222                ParametersUtil.addParameterToParametersCode(
223                                myCtx, retVal, ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME, theOutput.getName());
224                if (isNotBlank(theOutput.getDescription())) {
225                        ParametersUtil.addParameterToParametersString(
226                                        myCtx, retVal, ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC, theOutput.getDescription());
227                }
228                return retVal;
229        }
230
231        private IBaseParameters prepareOutputList(List<PartitionEntity> theOutput) {
232                IBaseParameters retVal = ParametersUtil.newInstance(myCtx);
233                for (PartitionEntity partitionEntity : theOutput) {
234                        IBase resultPart = ParametersUtil.addParameterToParameters(myCtx, retVal, "partition");
235                        ParametersUtil.addPartInteger(
236                                        myCtx, resultPart, ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, partitionEntity.getId());
237                        ParametersUtil.addPartCode(
238                                        myCtx,
239                                        resultPart,
240                                        ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME,
241                                        partitionEntity.getName());
242                        if (isNotBlank(partitionEntity.getDescription())) {
243                                ParametersUtil.addPartString(
244                                                myCtx,
245                                                resultPart,
246                                                ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC,
247                                                partitionEntity.getDescription());
248                        }
249                }
250                return retVal;
251        }
252
253        @Nonnull
254        private PartitionEntity parseInput(
255                        @OperationParam(
256                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID,
257                                                        min = 1,
258                                                        max = 1,
259                                                        typeName = "integer")
260                                        IPrimitiveType<Integer> thePartitionId,
261                        @OperationParam(
262                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME,
263                                                        min = 1,
264                                                        max = 1,
265                                                        typeName = "code")
266                                        IPrimitiveType<String> thePartitionName,
267                        @OperationParam(
268                                                        name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC,
269                                                        min = 0,
270                                                        max = 1,
271                                                        typeName = "string")
272                                        IPrimitiveType<String> thePartitionDescription) {
273                PartitionEntity input = new PartitionEntity();
274                if (thePartitionId != null) {
275                        input.setId(thePartitionId.getValue());
276                }
277                if (thePartitionName != null) {
278                        input.setName(thePartitionName.getValue());
279                }
280                if (thePartitionDescription != null) {
281                        input.setDescription(thePartitionDescription.getValue());
282                }
283                return input;
284        }
285}