View Javadoc
1   package ca.uhn.fhir.jpa.entity;
2   
3   /*
4    * #%L
5    * HAPI FHIR JPA Server
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import ca.uhn.fhir.model.api.IQueryParameterType;
24  import ca.uhn.fhir.util.UrlUtil;
25  import com.google.common.base.Charsets;
26  import com.google.common.hash.HashCode;
27  import com.google.common.hash.HashFunction;
28  import com.google.common.hash.Hasher;
29  import com.google.common.hash.Hashing;
30  import org.hibernate.search.annotations.ContainedIn;
31  import org.hibernate.search.annotations.Field;
32  
33  import javax.persistence.*;
34  import java.io.Serializable;
35  import java.util.Date;
36  
37  @MappedSuperclass
38  public abstract class BaseResourceIndexedSearchParam implements Serializable {
39  	static final int MAX_SP_NAME = 100;
40  	/**
41  	 * Don't change this without careful consideration. You will break existing hashes!
42  	 */
43  	private static final HashFunction HASH_FUNCTION = Hashing.murmur3_128(0);
44  	/**
45  	 * Don't make this public 'cause nobody better be able to modify it!
46  	 */
47  	private static final byte[] DELIMITER_BYTES = "|".getBytes(Charsets.UTF_8);
48  	private static final long serialVersionUID = 1L;
49  
50  	// TODO: make this nullable=false and a primitive (written may 2017)
51  	@Field()
52  	@Column(name = "SP_MISSING", nullable = true)
53  	private Boolean myMissing = Boolean.FALSE;
54  
55  	@Field
56  	@Column(name = "SP_NAME", length = MAX_SP_NAME, nullable = false)
57  	private String myParamName;
58  
59  	@ManyToOne(optional = false, fetch = FetchType.LAZY)
60  	@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID")
61  	@ContainedIn
62  	private ResourceTable myResource;
63  
64  	@Column(name = "RES_ID", insertable = false, updatable = false)
65  	private Long myResourcePid;
66  
67  	@Field()
68  	@Column(name = "RES_TYPE", nullable = false)
69  	private String myResourceType;
70  
71  	@Field()
72  	@Column(name = "SP_UPDATED", nullable = true) // TODO: make this false after HAPI 2.3
73  	@Temporal(TemporalType.TIMESTAMP)
74  	private Date myUpdated;
75  
76  	/**
77  	 * Subclasses may override
78  	 */
79  	protected void clearHashes() {
80  		// nothing
81  	}
82  
83  	protected abstract Long getId();
84  
85  	public String getParamName() {
86  		return myParamName;
87  	}
88  
89  	public void setParamName(String theName) {
90  		clearHashes();
91  		myParamName = theName;
92  	}
93  
94  	public ResourceTable getResource() {
95  		return myResource;
96  	}
97  
98  	public BaseResourceIndexedSearchParam setResource(ResourceTable theResource) {
99  		clearHashes();
100 		myResource = theResource;
101 		myResourceType = theResource.getResourceType();
102 		return this;
103 	}
104 
105 	public Long getResourcePid() {
106 		return myResourcePid;
107 	}
108 
109 	public String getResourceType() {
110 		return myResourceType;
111 	}
112 
113 	public Date getUpdated() {
114 		return myUpdated;
115 	}
116 
117 	public void setUpdated(Date theUpdated) {
118 		myUpdated = theUpdated;
119 	}
120 
121 	public boolean isMissing() {
122 		return Boolean.TRUE.equals(myMissing);
123 	}
124 
125 	public BaseResourceIndexedSearchParam setMissing(boolean theMissing) {
126 		myMissing = theMissing;
127 		return this;
128 	}
129 
130 	public abstract IQueryParameterType toQueryParameterType();
131 
132 	public static long calculateHashIdentity(String theResourceType, String theParamName) {
133 		return hash(theResourceType, theParamName);
134 	}
135 
136 	/**
137 	 * Applies a fast and consistent hashing algorithm to a set of strings
138 	 */
139 	static long hash(String... theValues) {
140 		Hasher hasher = HASH_FUNCTION.newHasher();
141 
142 		for (String next : theValues) {
143 			if (next == null) {
144 				hasher.putByte((byte) 0);
145 			} else {
146 				next = UrlUtil.escapeUrlParam(next);
147 				byte[] bytes = next.getBytes(Charsets.UTF_8);
148 				hasher.putBytes(bytes);
149 			}
150 			hasher.putBytes(DELIMITER_BYTES);
151 		}
152 
153 		HashCode hashCode = hasher.hash();
154 		return hashCode.asLong();
155 	}
156 
157 }