
001package ca.uhn.fhir.interceptor.model; 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.model.api.IModelJson; 024import ca.uhn.fhir.util.JsonUtil; 025import com.fasterxml.jackson.annotation.JsonProperty; 026import com.fasterxml.jackson.core.JsonProcessingException; 027import com.fasterxml.jackson.databind.ObjectMapper; 028import org.apache.commons.lang3.Validate; 029import org.apache.commons.lang3.builder.EqualsBuilder; 030import org.apache.commons.lang3.builder.HashCodeBuilder; 031import org.apache.commons.lang3.builder.ToStringBuilder; 032import org.apache.commons.lang3.builder.ToStringStyle; 033 034import javax.annotation.Nonnull; 035import javax.annotation.Nullable; 036import java.time.LocalDate; 037import java.util.ArrayList; 038import java.util.Arrays; 039import java.util.Collection; 040import java.util.Collections; 041import java.util.List; 042import java.util.stream.Collectors; 043 044import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 045 046/** 047 * @since 5.0.0 048 */ 049public class RequestPartitionId implements IModelJson { 050 private static final RequestPartitionId ALL_PARTITIONS = new RequestPartitionId(); 051 private static final ObjectMapper ourObjectMapper = new ObjectMapper().registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()); 052 @JsonProperty("partitionDate") 053 private final LocalDate myPartitionDate; 054 @JsonProperty("allPartitions") 055 private final boolean myAllPartitions; 056 @JsonProperty("partitionIds") 057 private final List<Integer> myPartitionIds; 058 @JsonProperty("partitionNames") 059 private final List<String> myPartitionNames; 060 061 /** 062 * Constructor for a single partition 063 */ 064 private RequestPartitionId(@Nullable String thePartitionName, @Nullable Integer thePartitionId, @Nullable LocalDate thePartitionDate) { 065 myPartitionIds = toListOrNull(thePartitionId); 066 myPartitionNames = toListOrNull(thePartitionName); 067 myPartitionDate = thePartitionDate; 068 myAllPartitions = false; 069 } 070 071 /** 072 * Constructor for a multiple partition 073 */ 074 private RequestPartitionId(@Nullable List<String> thePartitionName, @Nullable List<Integer> thePartitionId, @Nullable LocalDate thePartitionDate) { 075 myPartitionIds = toListOrNull(thePartitionId); 076 myPartitionNames = toListOrNull(thePartitionName); 077 myPartitionDate = thePartitionDate; 078 myAllPartitions = false; 079 } 080 081 /** 082 * Constructor for all partitions 083 */ 084 private RequestPartitionId() { 085 super(); 086 myPartitionDate = null; 087 myPartitionNames = null; 088 myPartitionIds = null; 089 myAllPartitions = true; 090 } 091 092 public static RequestPartitionId fromJson(String theJson) throws JsonProcessingException { 093 return ourObjectMapper.readValue(theJson, RequestPartitionId.class); 094 } 095 096 public boolean isAllPartitions() { 097 return myAllPartitions; 098 } 099 100 @Nullable 101 public LocalDate getPartitionDate() { 102 return myPartitionDate; 103 } 104 105 @Nullable 106 public List<String> getPartitionNames() { 107 return myPartitionNames; 108 } 109 110 @Nonnull 111 public List<Integer> getPartitionIds() { 112 Validate.notNull(myPartitionIds, "Partition IDs have not been set"); 113 return myPartitionIds; 114 } 115 116 @Override 117 public String toString() { 118 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 119 if (hasPartitionIds()) { 120 b.append("ids", getPartitionIds()); 121 } 122 if (hasPartitionNames()) { 123 b.append("names", getPartitionNames()); 124 } 125 return b.build(); 126 } 127 128 @Override 129 public boolean equals(Object theO) { 130 if (this == theO) { 131 return true; 132 } 133 134 if (theO == null || getClass() != theO.getClass()) { 135 return false; 136 } 137 138 RequestPartitionId that = (RequestPartitionId) theO; 139 140 EqualsBuilder b = new EqualsBuilder(); 141 b.append(myAllPartitions, that.myAllPartitions); 142 b.append(myPartitionDate, that.myPartitionDate); 143 b.append(myPartitionIds, that.myPartitionIds); 144 b.append(myPartitionNames, that.myPartitionNames); 145 return b.isEquals(); 146 } 147 148 @Override 149 public int hashCode() { 150 return new HashCodeBuilder(17, 37) 151 .append(myPartitionDate) 152 .append(myAllPartitions) 153 .append(myPartitionIds) 154 .append(myPartitionNames) 155 .toHashCode(); 156 } 157 158 public String toJson() { 159 return JsonUtil.serializeOrInvalidRequest(this); 160 } 161 162 @Nullable 163 public Integer getFirstPartitionIdOrNull() { 164 if (myPartitionIds != null) { 165 return myPartitionIds.get(0); 166 } 167 return null; 168 } 169 170 public String getFirstPartitionNameOrNull() { 171 if (myPartitionNames != null) { 172 return myPartitionNames.get(0); 173 } 174 return null; 175 } 176 177 /** 178 * Returns true if this request partition contains only one partition ID and it is the DEFAULT partition ID (null) 179 */ 180 public boolean isDefaultPartition() { 181 if (isAllPartitions()) { 182 return false; 183 } 184 return hasPartitionIds() && getPartitionIds().size() == 1 && getPartitionIds().get(0) == null; 185 } 186 187 public boolean hasPartitionId(Integer thePartitionId) { 188 Validate.notNull(myPartitionIds, "Partition IDs not set"); 189 return myPartitionIds.contains(thePartitionId); 190 } 191 192 public boolean hasPartitionIds() { 193 return myPartitionIds != null; 194 } 195 196 public boolean hasPartitionNames() { 197 return myPartitionNames != null; 198 } 199 200 public boolean hasDefaultPartitionId() { 201 return getPartitionIds().contains(null); 202 } 203 204 public List<Integer> getPartitionIdsWithoutDefault() { 205 return getPartitionIds().stream().filter(t -> t != null).collect(Collectors.toList()); 206 } 207 208 @Nullable 209 private static <T> List<T> toListOrNull(@Nullable Collection<T> theList) { 210 if (theList != null) { 211 if (theList.size() == 1) { 212 return Collections.singletonList(theList.iterator().next()); 213 } 214 return Collections.unmodifiableList(new ArrayList<>(theList)); 215 } 216 return null; 217 } 218 219 @Nullable 220 private static <T> List<T> toListOrNull(@Nullable T theObject) { 221 if (theObject != null) { 222 return Collections.singletonList(theObject); 223 } 224 return null; 225 } 226 227 @SafeVarargs 228 @Nullable 229 private static <T> List<T> toListOrNull(@Nullable T... theObject) { 230 if (theObject != null) { 231 return Arrays.asList(theObject); 232 } 233 return null; 234 } 235 236 @Nonnull 237 public static RequestPartitionId allPartitions() { 238 return ALL_PARTITIONS; 239 } 240 241 @Nonnull 242 public static RequestPartitionId defaultPartition() { 243 return fromPartitionIds(Collections.singletonList(null)); 244 } 245 246 @Nonnull 247 public static RequestPartitionId defaultPartition(@Nullable LocalDate thePartitionDate) { 248 return fromPartitionIds(Collections.singletonList(null), thePartitionDate); 249 } 250 251 @Nonnull 252 public static RequestPartitionId fromPartitionId(@Nullable Integer thePartitionId) { 253 return fromPartitionIds(Collections.singletonList(thePartitionId)); 254 } 255 256 @Nonnull 257 public static RequestPartitionId fromPartitionId(@Nullable Integer thePartitionId, @Nullable LocalDate thePartitionDate) { 258 return new RequestPartitionId(null, Collections.singletonList(thePartitionId), thePartitionDate); 259 } 260 261 @Nonnull 262 public static RequestPartitionId fromPartitionIds(@Nonnull Collection<Integer> thePartitionIds) { 263 return fromPartitionIds(thePartitionIds, null); 264 } 265 266 @Nonnull 267 public static RequestPartitionId fromPartitionIds(@Nonnull Collection<Integer> thePartitionIds, @Nullable LocalDate thePartitionDate) { 268 return new RequestPartitionId(null, toListOrNull(thePartitionIds), thePartitionDate); 269 } 270 271 @Nonnull 272 public static RequestPartitionId fromPartitionIds(Integer... thePartitionIds) { 273 return new RequestPartitionId(null, toListOrNull(thePartitionIds), null); 274 } 275 276 @Nonnull 277 public static RequestPartitionId fromPartitionName(@Nullable String thePartitionName) { 278 return fromPartitionName(thePartitionName, null); 279 } 280 281 @Nonnull 282 public static RequestPartitionId fromPartitionName(@Nullable String thePartitionName, @Nullable LocalDate thePartitionDate) { 283 return new RequestPartitionId(thePartitionName, null, thePartitionDate); 284 } 285 286 @Nonnull 287 public static RequestPartitionId fromPartitionNames(@Nullable List<String> thePartitionNames) { 288 return new RequestPartitionId(toListOrNull(thePartitionNames), null, null); 289 } 290 291 @Nonnull 292 public static RequestPartitionId fromPartitionNames(String... thePartitionNames) { 293 return new RequestPartitionId(toListOrNull(thePartitionNames), null, null); 294 } 295 296 @Nonnull 297 public static RequestPartitionId fromPartitionIdAndName(@Nullable Integer thePartitionId, @Nullable String thePartitionName) { 298 return new RequestPartitionId(thePartitionName, thePartitionId, null); 299 } 300 301 @Nonnull 302 public static RequestPartitionId forPartitionIdAndName(@Nullable Integer thePartitionId, @Nullable String thePartitionName, @Nullable LocalDate thePartitionDate) { 303 return new RequestPartitionId(thePartitionName, thePartitionId, thePartitionDate); 304 } 305 306 @Nonnull 307 public static RequestPartitionId forPartitionIdsAndNames(List<String> thePartitionNames, List<Integer> thePartitionIds, LocalDate thePartitionDate) { 308 return new RequestPartitionId(thePartitionNames, thePartitionIds, thePartitionDate); 309 } 310 311 /** 312 * Create a string representation suitable for use as a cache key. Null aware. 313 * <p> 314 * Returns the partition IDs (numeric) as a joined string with a space between, using the string "null" for any null values 315 */ 316 public static String stringifyForKey(@Nonnull RequestPartitionId theRequestPartitionId) { 317 String retVal = "(all)"; 318 if (!theRequestPartitionId.isAllPartitions()) { 319 assert theRequestPartitionId.hasPartitionIds(); 320 retVal = theRequestPartitionId 321 .getPartitionIds() 322 .stream() 323 .map(t -> defaultIfNull(t, "null").toString()) 324 .collect(Collectors.joining(" ")); 325 } 326 return retVal; 327 } 328 329 public String asJson() throws JsonProcessingException { 330 return ourObjectMapper.writeValueAsString(this); 331 } 332}