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}