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.jpa.search.IndexNonDeletedInterceptor;
24  import ca.uhn.fhir.model.primitive.IdDt;
25  import ca.uhn.fhir.rest.api.Constants;
26  import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
27  import org.apache.commons.lang3.builder.ToStringBuilder;
28  import org.apache.commons.lang3.builder.ToStringStyle;
29  import org.hibernate.annotations.OptimisticLock;
30  import org.hibernate.search.annotations.*;
31  
32  import javax.persistence.*;
33  import javax.persistence.Index;
34  import java.io.Serializable;
35  import java.util.ArrayList;
36  import java.util.Collection;
37  import java.util.HashSet;
38  import java.util.Set;
39  
40  import static org.apache.commons.lang3.StringUtils.defaultString;
41  
42  @Indexed(interceptor = IndexNonDeletedInterceptor.class)
43  @Entity
44  @Table(name = "HFJ_RESOURCE", uniqueConstraints = {}, indexes = {
45  	@Index(name = "IDX_RES_DATE", columnList = "RES_UPDATED"),
46  	@Index(name = "IDX_RES_LANG", columnList = "RES_TYPE,RES_LANGUAGE"),
47  	@Index(name = "IDX_RES_PROFILE", columnList = "RES_PROFILE"),
48  	@Index(name = "IDX_RES_TYPE", columnList = "RES_TYPE"),
49  	@Index(name = "IDX_INDEXSTATUS", columnList = "SP_INDEX_STATUS")
50  })
51  public class ResourceTable extends BaseHasResource implements Serializable {
52  	static final int RESTYPE_LEN = 30;
53  	private static final int MAX_LANGUAGE_LENGTH = 20;
54  	private static final int MAX_PROFILE_LENGTH = 200;
55  	private static final long serialVersionUID = 1L;
56  
57  //	@Transient
58  //	private transient byte[] myResource;
59  //
60  //	@Transient
61  //	private transient ResourceEncodingEnum myEncoding;
62  
63  	/**
64  	 * Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB
65  	 */
66  	@Transient()
67  	@Fields({
68  		@Field(name = "myContentText", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
69  		@Field(name = "myContentTextEdgeNGram", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
70  		@Field(name = "myContentTextNGram", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteNGramAnalyzer")),
71  		@Field(name = "myContentTextPhonetic", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompletePhoneticAnalyzer"))
72  	})
73  	@OptimisticLock(excluded = true)
74  	private String myContentText;
75  
76  	@Column(name = "HASH_SHA256", length = 64, nullable = true)
77  	@OptimisticLock(excluded = true)
78  	private String myHashSha256;
79  
80  	@Column(name = "SP_HAS_LINKS")
81  	@OptimisticLock(excluded = true)
82  	private boolean myHasLinks;
83  
84  	@Id
85  	@SequenceGenerator(name = "SEQ_RESOURCE_ID", sequenceName = "SEQ_RESOURCE_ID")
86  	@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESOURCE_ID")
87  	@Column(name = "RES_ID")
88  	private Long myId;
89  
90  	@OneToMany(mappedBy = "myTargetResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
91  	@OptimisticLock(excluded = true)
92  	private Collection<ResourceLink> myIncomingResourceLinks;
93  
94  	@Column(name = "SP_INDEX_STATUS", nullable = true)
95  	@OptimisticLock(excluded = true)
96  	private Long myIndexStatus;
97  
98  	@Column(name = "RES_LANGUAGE", length = MAX_LANGUAGE_LENGTH, nullable = true)
99  	@OptimisticLock(excluded = true)
100 	private String myLanguage;
101 
102 	/**
103 	 * Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB
104 	 */
105 	@Transient()
106 	@Fields({
107 		@Field(name = "myNarrativeText", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
108 		@Field(name = "myNarrativeTextEdgeNGram", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
109 		@Field(name = "myNarrativeTextNGram", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteNGramAnalyzer")),
110 		@Field(name = "myNarrativeTextPhonetic", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompletePhoneticAnalyzer"))
111 	})
112 	@OptimisticLock(excluded = true)
113 	private String myNarrativeText;
114 
115 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
116 	@OptimisticLock(excluded = true)
117 	private Collection<ResourceIndexedSearchParamCoords> myParamsCoords;
118 
119 	@Column(name = "SP_COORDS_PRESENT")
120 	@OptimisticLock(excluded = true)
121 	private boolean myParamsCoordsPopulated;
122 
123 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
124 	@OptimisticLock(excluded = true)
125 	private Collection<ResourceIndexedSearchParamDate> myParamsDate;
126 
127 	@Column(name = "SP_DATE_PRESENT")
128 	@OptimisticLock(excluded = true)
129 	private boolean myParamsDatePopulated;
130 
131 	@OptimisticLock(excluded = true)
132 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
133 	private Collection<ResourceIndexedSearchParamNumber> myParamsNumber;
134 
135 	@Column(name = "SP_NUMBER_PRESENT")
136 	@OptimisticLock(excluded = true)
137 	private boolean myParamsNumberPopulated;
138 
139 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
140 	@OptimisticLock(excluded = true)
141 	private Collection<ResourceIndexedSearchParamQuantity> myParamsQuantity;
142 
143 	@Column(name = "SP_QUANTITY_PRESENT")
144 	@OptimisticLock(excluded = true)
145 	private boolean myParamsQuantityPopulated;
146 
147 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
148 	@OptimisticLock(excluded = true)
149 	private Collection<ResourceIndexedSearchParamString> myParamsString;
150 
151 	@Column(name = "SP_STRING_PRESENT")
152 	@OptimisticLock(excluded = true)
153 	private boolean myParamsStringPopulated;
154 
155 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
156 	@OptimisticLock(excluded = true)
157 	private Collection<ResourceIndexedSearchParamToken> myParamsToken;
158 
159 	@Column(name = "SP_TOKEN_PRESENT")
160 	@OptimisticLock(excluded = true)
161 	private boolean myParamsTokenPopulated;
162 
163 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
164 	@OptimisticLock(excluded = true)
165 	private Collection<ResourceIndexedSearchParamUri> myParamsUri;
166 
167 	@Column(name = "SP_URI_PRESENT")
168 	@OptimisticLock(excluded = true)
169 	private boolean myParamsUriPopulated;
170 
171 	@Column(name = "RES_PROFILE", length = MAX_PROFILE_LENGTH, nullable = true)
172 	@OptimisticLock(excluded = true)
173 	private String myProfile;
174 
175 	// Added in 3.0.0 - Should make this a primitive Boolean at some point
176 	@OptimisticLock(excluded = true)
177 	@Column(name = "SP_CMPSTR_UNIQ_PRESENT")
178 	private Boolean myParamsCompositeStringUniquePresent = false;
179 
180 	@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
181 	@OptimisticLock(excluded = true)
182 	private Collection<ResourceIndexedCompositeStringUnique> myParamsCompositeStringUnique;
183 
184 	@OneToMany(mappedBy = "mySourceResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
185 	@IndexedEmbedded()
186 	@OptimisticLock(excluded = true)
187 	private Collection<ResourceLink> myResourceLinks;
188 
189 	@Column(name = "RES_TYPE", length = RESTYPE_LEN)
190 	@Field
191 	@OptimisticLock(excluded = true)
192 	private String myResourceType;
193 
194 	@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
195 	@OptimisticLock(excluded = true)
196 	private Collection<SearchParamPresent> mySearchParamPresents;
197 
198 	@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
199 	@OptimisticLock(excluded = true)
200 	private Set<ResourceTag> myTags;
201 
202 	@Transient
203 	private transient boolean myUnchangedInCurrentOperation;
204 
205 	@Version
206 	@Column(name = "RES_VER")
207 	private long myVersion;
208 
209 	@Override
210 	public ResourceTag addTag(TagDefinition theTag) {
211 		for (ResourceTag next : getTags()) {
212 			if (next.getTag().equals(theTag)) {
213 				return next;
214 			}
215 		}
216 		ResourceTag tag = new ResourceTag(this, theTag);
217 		getTags().add(tag);
218 		return tag;
219 	}
220 
221 //	public ResourceEncodingEnum getEncoding() {
222 //		Validate.notNull(myEncoding, "myEncoding is null");
223 //		return myEncoding;
224 //	}
225 //
226 //	public void setEncoding(ResourceEncodingEnum theEncoding) {
227 //		myEncoding = theEncoding;
228 //	}
229 
230 	public String getHashSha256() {
231 		return myHashSha256;
232 	}
233 
234 	public void setHashSha256(String theHashSha256) {
235 		myHashSha256 = theHashSha256;
236 	}
237 
238 	@Override
239 	public Long getId() {
240 		return myId;
241 	}
242 
243 	public void setId(Long theId) {
244 		myId = theId;
245 	}
246 
247 	@Override
248 	public IdDt getIdDt() {
249 		if (getForcedId() == null) {
250 			Long id = myId;
251 			return new IdDt(myResourceType + '/' + id + '/' + Constants.PARAM_HISTORY + '/' + myVersion);
252 		} else {
253 			return new IdDt(getForcedId().getResourceType() + '/' + getForcedId().getForcedId() + '/' + Constants.PARAM_HISTORY + '/' + myVersion);
254 		}
255 	}
256 
257 	public Long getIndexStatus() {
258 		return myIndexStatus;
259 	}
260 
261 	public void setIndexStatus(Long theIndexStatus) {
262 		myIndexStatus = theIndexStatus;
263 	}
264 
265 	public String getLanguage() {
266 		return myLanguage;
267 	}
268 
269 	public void setLanguage(String theLanguage) {
270 		if (defaultString(theLanguage).length() > MAX_LANGUAGE_LENGTH) {
271 			throw new UnprocessableEntityException("Language exceeds maximum length of " + MAX_LANGUAGE_LENGTH + " chars: " + theLanguage);
272 		}
273 		myLanguage = theLanguage;
274 	}
275 
276 	public Collection<ResourceIndexedCompositeStringUnique> getParamsCompositeStringUnique() {
277 		if (myParamsCompositeStringUnique == null) {
278 			myParamsCompositeStringUnique = new ArrayList<>();
279 		}
280 		return myParamsCompositeStringUnique;
281 	}
282 
283 	public void setParamsCompositeStringUnique(Collection<ResourceIndexedCompositeStringUnique> theParamsCompositeStringUnique) {
284 		myParamsCompositeStringUnique = theParamsCompositeStringUnique;
285 	}
286 
287 	public Collection<ResourceIndexedSearchParamCoords> getParamsCoords() {
288 		if (myParamsCoords == null) {
289 			myParamsCoords = new ArrayList<>();
290 		}
291 		return myParamsCoords;
292 	}
293 
294 	public void setParamsCoords(Collection<ResourceIndexedSearchParamCoords> theParamsCoords) {
295 		if (!isParamsTokenPopulated() && theParamsCoords.isEmpty()) {
296 			return;
297 		}
298 		getParamsCoords().clear();
299 		getParamsCoords().addAll(theParamsCoords);
300 	}
301 
302 	public Collection<ResourceIndexedSearchParamDate> getParamsDate() {
303 		if (myParamsDate == null) {
304 			myParamsDate = new ArrayList<>();
305 		}
306 		return myParamsDate;
307 	}
308 
309 	public void setParamsDate(Collection<ResourceIndexedSearchParamDate> theParamsDate) {
310 		if (!isParamsDatePopulated() && theParamsDate.isEmpty()) {
311 			return;
312 		}
313 		getParamsDate().clear();
314 		getParamsDate().addAll(theParamsDate);
315 	}
316 
317 	public Collection<ResourceIndexedSearchParamNumber> getParamsNumber() {
318 		if (myParamsNumber == null) {
319 			myParamsNumber = new ArrayList<>();
320 		}
321 		return myParamsNumber;
322 	}
323 
324 	public void setParamsNumber(Collection<ResourceIndexedSearchParamNumber> theNumberParams) {
325 		if (!isParamsNumberPopulated() && theNumberParams.isEmpty()) {
326 			return;
327 		}
328 		getParamsNumber().clear();
329 		getParamsNumber().addAll(theNumberParams);
330 	}
331 
332 	public Collection<ResourceIndexedSearchParamQuantity> getParamsQuantity() {
333 		if (myParamsQuantity == null) {
334 			myParamsQuantity = new ArrayList<>();
335 		}
336 		return myParamsQuantity;
337 	}
338 
339 	public void setParamsQuantity(Collection<ResourceIndexedSearchParamQuantity> theQuantityParams) {
340 		if (!isParamsQuantityPopulated() && theQuantityParams.isEmpty()) {
341 			return;
342 		}
343 		getParamsQuantity().clear();
344 		getParamsQuantity().addAll(theQuantityParams);
345 	}
346 
347 	public Collection<ResourceIndexedSearchParamString> getParamsString() {
348 		if (myParamsString == null) {
349 			myParamsString = new ArrayList<>();
350 		}
351 		return myParamsString;
352 	}
353 
354 	public void setParamsString(Collection<ResourceIndexedSearchParamString> theParamsString) {
355 		if (!isParamsStringPopulated() && theParamsString.isEmpty()) {
356 			return;
357 		}
358 		getParamsString().clear();
359 		getParamsString().addAll(theParamsString);
360 	}
361 
362 	public Collection<ResourceIndexedSearchParamToken> getParamsToken() {
363 		if (myParamsToken == null) {
364 			myParamsToken = new ArrayList<>();
365 		}
366 		return myParamsToken;
367 	}
368 
369 	public void setParamsToken(Collection<ResourceIndexedSearchParamToken> theParamsToken) {
370 		if (!isParamsTokenPopulated() && theParamsToken.isEmpty()) {
371 			return;
372 		}
373 		getParamsToken().clear();
374 		getParamsToken().addAll(theParamsToken);
375 	}
376 
377 	public Collection<ResourceIndexedSearchParamUri> getParamsUri() {
378 		if (myParamsUri == null) {
379 			myParamsUri = new ArrayList<>();
380 		}
381 		return myParamsUri;
382 	}
383 
384 	public void setParamsUri(Collection<ResourceIndexedSearchParamUri> theParamsUri) {
385 		if (!isParamsTokenPopulated() && theParamsUri.isEmpty()) {
386 			return;
387 		}
388 		getParamsUri().clear();
389 		getParamsUri().addAll(theParamsUri);
390 	}
391 
392 	public String getProfile() {
393 		return myProfile;
394 	}
395 
396 	public void setProfile(String theProfile) {
397 		if (defaultString(theProfile).length() > MAX_PROFILE_LENGTH) {
398 			throw new UnprocessableEntityException("Profile name exceeds maximum length of " + MAX_PROFILE_LENGTH + " chars: " + theProfile);
399 		}
400 		myProfile = theProfile;
401 	}
402 
403 	@Override
404 	public Long getResourceId() {
405 		return getId();
406 	}
407 
408 //	public byte[] getResource() {
409 //		Validate.notNull(myEncoding, "myEncoding is null");
410 //		return myResource;
411 //	}
412 //
413 //	public void setResource(byte[] theResource) {
414 //		myResource = theResource;
415 //	}
416 
417 	public Collection<ResourceLink> getResourceLinks() {
418 		if (myResourceLinks == null) {
419 			myResourceLinks = new ArrayList<>();
420 		}
421 		return myResourceLinks;
422 	}
423 
424 	public void setResourceLinks(Collection<ResourceLink> theLinks) {
425 		if (!isHasLinks() && theLinks.isEmpty()) {
426 			return;
427 		}
428 		getResourceLinks().clear();
429 		getResourceLinks().addAll(theLinks);
430 	}
431 
432 	@Override
433 	public String getResourceType() {
434 		return myResourceType;
435 	}
436 
437 	public ResourceTable setResourceType(String theResourceType) {
438 		myResourceType = theResourceType;
439 		return this;
440 	}
441 
442 	@Override
443 	public Collection<ResourceTag> getTags() {
444 		if (myTags == null) {
445 			myTags = new HashSet<>();
446 		}
447 		return myTags;
448 	}
449 
450 	@Override
451 	public long getVersion() {
452 		return myVersion;
453 	}
454 
455 	public void setVersion(long theVersion) {
456 		myVersion = theVersion;
457 	}
458 
459 	public boolean isHasLinks() {
460 		return myHasLinks;
461 	}
462 
463 	public void setHasLinks(boolean theHasLinks) {
464 		myHasLinks = theHasLinks;
465 	}
466 
467 	public boolean isParamsCompositeStringUniquePresent() {
468 		if (myParamsCompositeStringUniquePresent == null) {
469 			return false;
470 		}
471 		return myParamsCompositeStringUniquePresent;
472 	}
473 
474 	public void setParamsCompositeStringUniquePresent(boolean theParamsCompositeStringUniquePresent) {
475 		myParamsCompositeStringUniquePresent = theParamsCompositeStringUniquePresent;
476 	}
477 
478 	public boolean isParamsCoordsPopulated() {
479 		return myParamsCoordsPopulated;
480 	}
481 
482 	public void setParamsCoordsPopulated(boolean theParamsCoordsPopulated) {
483 		myParamsCoordsPopulated = theParamsCoordsPopulated;
484 	}
485 
486 	public boolean isParamsDatePopulated() {
487 		return myParamsDatePopulated;
488 	}
489 
490 	public void setParamsDatePopulated(boolean theParamsDatePopulated) {
491 		myParamsDatePopulated = theParamsDatePopulated;
492 	}
493 
494 	public boolean isParamsNumberPopulated() {
495 		return myParamsNumberPopulated;
496 	}
497 
498 	public void setParamsNumberPopulated(boolean theParamsNumberPopulated) {
499 		myParamsNumberPopulated = theParamsNumberPopulated;
500 	}
501 
502 	public boolean isParamsQuantityPopulated() {
503 		return myParamsQuantityPopulated;
504 	}
505 
506 	public void setParamsQuantityPopulated(boolean theParamsQuantityPopulated) {
507 		myParamsQuantityPopulated = theParamsQuantityPopulated;
508 	}
509 
510 	public boolean isParamsStringPopulated() {
511 		return myParamsStringPopulated;
512 	}
513 
514 	public void setParamsStringPopulated(boolean theParamsStringPopulated) {
515 		myParamsStringPopulated = theParamsStringPopulated;
516 	}
517 
518 	public boolean isParamsTokenPopulated() {
519 		return myParamsTokenPopulated;
520 	}
521 
522 	public void setParamsTokenPopulated(boolean theParamsTokenPopulated) {
523 		myParamsTokenPopulated = theParamsTokenPopulated;
524 	}
525 
526 	public boolean isParamsUriPopulated() {
527 		return myParamsUriPopulated;
528 	}
529 
530 	public void setParamsUriPopulated(boolean theParamsUriPopulated) {
531 		myParamsUriPopulated = theParamsUriPopulated;
532 	}
533 
534 	/**
535 	 * Transient (not saved in DB) flag indicating that this resource was found to be unchanged by the current operation
536 	 * and was not re-saved in the database
537 	 */
538 	public boolean isUnchangedInCurrentOperation() {
539 		return myUnchangedInCurrentOperation;
540 	}
541 
542 	/**
543 	 * Transient (not saved in DB) flag indicating that this resource was found to be unchanged by the current operation
544 	 * and was not re-saved in the database
545 	 */
546 	public void setUnchangedInCurrentOperation(boolean theUnchangedInCurrentOperation) {
547 		myUnchangedInCurrentOperation = theUnchangedInCurrentOperation;
548 	}
549 
550 	public void setContentTextParsedIntoWords(String theContentText) {
551 		myContentText = theContentText;
552 	}
553 
554 	public void setNarrativeTextParsedIntoWords(String theNarrativeText) {
555 		myNarrativeText = theNarrativeText;
556 	}
557 
558 	public ResourceHistoryTable toHistory() {
559 		ResourceHistoryTable retVal = new ResourceHistoryTable();
560 
561 		retVal.setResourceId(myId);
562 		retVal.setResourceType(myResourceType);
563 		retVal.setVersion(myVersion);
564 
565 		retVal.setPublished(getPublished());
566 		retVal.setUpdated(getUpdated());
567 //		retVal.setEncoding(getEncoding());
568 		retVal.setFhirVersion(getFhirVersion());
569 //		retVal.setResource(getResource());
570 		retVal.setDeleted(getDeleted());
571 		retVal.setForcedId(getForcedId());
572 
573 		retVal.getTags().clear();
574 
575 		retVal.setHasTags(isHasTags());
576 		if (isHasTags()) {
577 			for (ResourceTag next : getTags()) {
578 				retVal.addTag(next);
579 			}
580 		}
581 
582 		return retVal;
583 	}
584 
585 	@Override
586 	public String toString() {
587 		ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
588 		b.append("resourceType", myResourceType);
589 		b.append("pid", myId);
590 		return b.build();
591 	}
592 
593 }