001/* 002 * #%L 003 * HAPI FHIR JPA Model 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.model.entity; 021 022import ca.uhn.fhir.interceptor.model.RequestPartitionId; 023import ca.uhn.fhir.jpa.model.config.PartitionSettings; 024import ca.uhn.fhir.model.api.IQueryParameterType; 025import ca.uhn.fhir.rest.param.UriParam; 026import jakarta.persistence.Column; 027import jakarta.persistence.Embeddable; 028import jakarta.persistence.Entity; 029import jakarta.persistence.FetchType; 030import jakarta.persistence.ForeignKey; 031import jakarta.persistence.GeneratedValue; 032import jakarta.persistence.GenerationType; 033import jakarta.persistence.Id; 034import jakarta.persistence.Index; 035import jakarta.persistence.JoinColumn; 036import jakarta.persistence.ManyToOne; 037import jakarta.persistence.SequenceGenerator; 038import jakarta.persistence.Table; 039import org.apache.commons.lang3.StringUtils; 040import org.apache.commons.lang3.builder.EqualsBuilder; 041import org.apache.commons.lang3.builder.HashCodeBuilder; 042import org.apache.commons.lang3.builder.ToStringBuilder; 043import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; 044 045import static org.apache.commons.lang3.StringUtils.defaultString; 046 047@Embeddable 048@Entity 049@Table( 050 name = "HFJ_SPIDX_URI", 051 indexes = { 052 // for queries 053 @Index(name = "IDX_SP_URI_HASH_URI_V2", columnList = "HASH_URI,RES_ID,PARTITION_ID", unique = true), 054 // for sorting 055 @Index( 056 name = "IDX_SP_URI_HASH_IDENTITY_V2", 057 columnList = "HASH_IDENTITY,SP_URI,RES_ID,PARTITION_ID", 058 unique = true), 059 // for index create/delete 060 @Index(name = "IDX_SP_URI_COORDS", columnList = "RES_ID") 061 }) 062public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchParam { 063 064 /* 065 * Be careful when modifying this value 066 * MySQL chokes on indexes with combined column length greater than 3052 bytes (768 chars) 067 * https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html 068 */ 069 public static final int MAX_LENGTH = 500; 070 071 private static final long serialVersionUID = 1L; 072 073 @Column(name = "SP_URI", nullable = true, length = MAX_LENGTH) 074 @FullTextField 075 public String myUri; 076 077 @Id 078 @SequenceGenerator(name = "SEQ_SPIDX_URI", sequenceName = "SEQ_SPIDX_URI") 079 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_URI") 080 @Column(name = "SP_ID") 081 private Long myId; 082 /** 083 * @since 3.4.0 - At some point this should be made not-null 084 */ 085 @Column(name = "HASH_URI", nullable = true) 086 private Long myHashUri; 087 /** 088 * @since 3.5.0 - At some point this should be made not-null 089 */ 090 @Column(name = "HASH_IDENTITY", nullable = true) 091 private Long myHashIdentity; 092 093 @ManyToOne( 094 optional = false, 095 fetch = FetchType.LAZY, 096 cascade = {}) 097 @JoinColumn( 098 foreignKey = @ForeignKey(name = "FKGXSREUTYMMFJUWDSWV3Y887DO"), 099 name = "RES_ID", 100 referencedColumnName = "RES_ID", 101 nullable = false) 102 private ResourceTable myResource; 103 104 /** 105 * Constructor 106 */ 107 public ResourceIndexedSearchParamUri() { 108 super(); 109 } 110 111 /** 112 * Constructor 113 */ 114 public ResourceIndexedSearchParamUri( 115 PartitionSettings thePartitionSettings, String theResourceType, String theParamName, String theUri) { 116 setPartitionSettings(thePartitionSettings); 117 setResourceType(theResourceType); 118 setParamName(theParamName); 119 setUri(theUri); 120 calculateHashes(); 121 } 122 123 @Override 124 public <T extends BaseResourceIndex> void copyMutableValuesFrom(T theSource) { 125 super.copyMutableValuesFrom(theSource); 126 ResourceIndexedSearchParamUri source = (ResourceIndexedSearchParamUri) theSource; 127 myUri = source.myUri; 128 myHashUri = source.myHashUri; 129 myHashIdentity = source.myHashIdentity; 130 } 131 132 @Override 133 public void clearHashes() { 134 myHashIdentity = null; 135 myHashUri = null; 136 } 137 138 @Override 139 public void calculateHashes() { 140 if (myHashIdentity != null || myHashUri != null) { 141 return; 142 } 143 144 String resourceType = getResourceType(); 145 String paramName = getParamName(); 146 String uri = getUri(); 147 setHashIdentity(calculateHashIdentity(getPartitionSettings(), getPartitionId(), resourceType, paramName)); 148 setHashUri(calculateHashUri(getPartitionSettings(), getPartitionId(), resourceType, paramName, uri)); 149 } 150 151 @Override 152 public boolean equals(Object theObj) { 153 if (this == theObj) { 154 return true; 155 } 156 if (theObj == null) { 157 return false; 158 } 159 if (!(theObj instanceof ResourceIndexedSearchParamUri)) { 160 return false; 161 } 162 ResourceIndexedSearchParamUri obj = (ResourceIndexedSearchParamUri) theObj; 163 EqualsBuilder b = new EqualsBuilder(); 164 b.append(getResourceType(), obj.getResourceType()); 165 b.append(getParamName(), obj.getParamName()); 166 b.append(getUri(), obj.getUri()); 167 b.append(getHashUri(), obj.getHashUri()); 168 b.append(getHashIdentity(), obj.getHashIdentity()); 169 return b.isEquals(); 170 } 171 172 private Long getHashIdentity() { 173 return myHashIdentity; 174 } 175 176 private void setHashIdentity(long theHashIdentity) { 177 myHashIdentity = theHashIdentity; 178 } 179 180 public Long getHashUri() { 181 return myHashUri; 182 } 183 184 public void setHashUri(Long theHashUri) { 185 myHashUri = theHashUri; 186 } 187 188 @Override 189 public Long getId() { 190 return myId; 191 } 192 193 @Override 194 public void setId(Long theId) { 195 myId = theId; 196 } 197 198 public String getUri() { 199 return myUri; 200 } 201 202 public ResourceIndexedSearchParamUri setUri(String theUri) { 203 myUri = StringUtils.defaultIfBlank(theUri, null); 204 return this; 205 } 206 207 @Override 208 public int hashCode() { 209 HashCodeBuilder b = new HashCodeBuilder(); 210 b.append(getResourceType()); 211 b.append(getParamName()); 212 b.append(getUri()); 213 b.append(getHashUri()); 214 b.append(getHashIdentity()); 215 return b.toHashCode(); 216 } 217 218 @Override 219 public IQueryParameterType toQueryParameterType() { 220 return new UriParam(getUri()); 221 } 222 223 @Override 224 public String toString() { 225 ToStringBuilder b = new ToStringBuilder(this); 226 b.append("id", getId()); 227 b.append("resourceId", getResourcePid()); 228 b.append("paramName", getParamName()); 229 b.append("uri", myUri); 230 b.append("hashUri", myHashUri); 231 return b.toString(); 232 } 233 234 @Override 235 public boolean matches(IQueryParameterType theParam) { 236 if (!(theParam instanceof UriParam)) { 237 return false; 238 } 239 UriParam uri = (UriParam) theParam; 240 return defaultString(getUri()).equalsIgnoreCase(uri.getValueNotNull()); 241 } 242 243 public static long calculateHashUri( 244 PartitionSettings thePartitionSettings, 245 PartitionablePartitionId theRequestPartitionId, 246 String theResourceType, 247 String theParamName, 248 String theUri) { 249 RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(theRequestPartitionId); 250 return calculateHashUri(thePartitionSettings, requestPartitionId, theResourceType, theParamName, theUri); 251 } 252 253 public static long calculateHashUri( 254 PartitionSettings thePartitionSettings, 255 RequestPartitionId theRequestPartitionId, 256 String theResourceType, 257 String theParamName, 258 String theUri) { 259 return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName, theUri); 260 } 261 262 @Override 263 public ResourceTable getResource() { 264 return myResource; 265 } 266 267 @Override 268 public BaseResourceIndexedSearchParam setResource(ResourceTable theResource) { 269 myResource = theResource; 270 setResourceType(theResource.getResourceType()); 271 return this; 272 } 273}