• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 25932489856

15 May 2026 05:43PM UTC coverage: 63.411% (-0.008%) from 63.419%
25932489856

Pull #6089

github

web-flow
Merge 93f301cec into 0dab4c409
Pull Request #6089: TRUNK-6635 Add search by LocationSearchCriteria, with option to find …

51 of 55 new or added lines in 3 files covered. (92.73%)

24 existing lines in 4 files now uncovered.

23308 of 36757 relevant lines covered (63.41%)

0.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.19
/api/src/main/java/org/openmrs/Location.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs;
11

12
import org.hibernate.annotations.BatchSize;
13
import org.hibernate.annotations.Cache;
14
import org.hibernate.annotations.CacheConcurrencyStrategy;
15
import org.hibernate.envers.Audited;
16
import org.openmrs.annotation.Independent;
17
import org.openmrs.api.APIException;
18
import org.openmrs.api.LocationService;
19
import org.openmrs.api.context.Context;
20
import javax.persistence.AttributeOverride;
21
import javax.persistence.Cacheable;
22
import javax.persistence.CascadeType;
23
import javax.persistence.Column;
24
import javax.persistence.Entity;
25
import javax.persistence.FetchType;
26
import javax.persistence.GeneratedValue;
27
import javax.persistence.GenerationType;
28
import javax.persistence.Id;
29
import javax.persistence.JoinColumn;
30
import javax.persistence.JoinTable;
31
import javax.persistence.ManyToMany;
32
import javax.persistence.ManyToOne;
33
import javax.persistence.OneToMany;
34
import javax.persistence.OrderBy;
35
import javax.persistence.Table;
36
import java.util.Collections;
37
import java.util.HashSet;
38
import java.util.List;
39
import java.util.Set;
40

41
/**
42
 * A Location is a physical place, such as a hospital, a room, a clinic, or a district. Locations
43
 * support a single hierarchy, such that each location may have one parent location. A
44
 * non-geographical grouping of locations, such as "All Community Health Centers" is not a location,
45
 * and should be modeled using {@link LocationTag}s.
46
 * Note: Prior to version 1.9 this class extended BaseMetadata
47
 */
48
@Entity
49
@Table(name = "location")
50
@Cacheable
51
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
52
@AttributeOverride(name = "attributes", column = @Column(name = "location_id"))
53
@Audited
54
public class Location extends BaseCustomizableMetadata<LocationAttribute> implements java.io.Serializable, Attributable<Location>, Address {
55
        
56
        public static final long serialVersionUID = 455634L;
57
        
58
        public static final int LOCATION_UNKNOWN = 1;
59
        
60
        // Fields
61
        @Id
62
        @Column(name = "location_id")
63
        @GeneratedValue(strategy = GenerationType.IDENTITY)
64
        private Integer locationId;
65
        
66
        @ManyToOne
67
        @JoinColumn(name = "location_type_concept_id")
68
        private Concept type;
69
        
70
        @Column(name = "address1")
71
        private String address1;
72
        
73
        @Column(name = "address2")
74
        private String address2;
75
        
76
        @Column(name = "city_village")
77
        private String cityVillage;
78
        
79
        @Column(name = "state_province")
80
        private String stateProvince;
81
        
82
        @Column(name = "country", length = 50)
83
        private String country;
84
        
85
        @Column(name = "postal_code", length = 50)
86
        private String postalCode;
87
        
88
        @Column(name = "latitude", length = 50)
89
        private String latitude;
90
        
91
        @Column(name = "longitude", length = 50)
92
        private String longitude;
93
        
94
        @Column(name = "county_district")
95
        private String countyDistrict;
96
        
97
        @Column(name = "address3")
98
        private String address3;
99
        
100
        @Column(name = "address4")
101
        private String address4;
102
        
103
        @Column(name = "address6")
104
        private String address6;
105
        
106
        @Column(name = "address5")
107
        private String address5;
108
        
109
        @Column(name = "address7")
110
        private String address7;
111
        
112
        @Column(name = "address8")
113
        private String address8;
114
        
115
        @Column(name = "address9")
116
        private String address9;
117
        
118
        @Column(name = "address10")
119
        private String address10;
120
        
121
        @Column(name = "address11")
122
        private String address11;
123
        
124
        @Column(name = "address12")
125
        private String address12;
126
        
127
        @Column(name = "address13")
128
        private String address13;
129
        
130
        @Column(name = "address14")
131
        private String address14;
132
        
133
        @Column(name = "address15")
134
        private String address15;
135

136
        @ManyToOne
137
        @JoinColumn(name = "parent_location")
138
        private Location parentLocation;
139
        
140
        @OneToMany(mappedBy = "parentLocation", cascade = CascadeType.ALL, orphanRemoval = true)
141
        @BatchSize(size = 100)
142
        @OrderBy("name")
143
        private Set<Location> childLocations;
144
        
145
        @ManyToMany(fetch = FetchType.LAZY)
146
        @JoinTable(
147
                name = "location_tag_map",
148
                joinColumns = @JoinColumn(name = "location_id"),
149
                inverseJoinColumns = @JoinColumn(name = "location_tag_id"))
150
        @BatchSize(size = 100)
151
        @Independent
152
        private Set<LocationTag> tags;
153
        
154
        // Constructors
155
        
156
        /** default constructor */
157
        public Location() {
1✔
158
        }
1✔
159
        
160
        /** constructor with id */
161
        public Location(Integer locationId) {
1✔
162
                this.locationId = locationId;
1✔
163
        }
1✔
164
        
165
        // Property accessors
166
        
167
        /**
168
         * @return Returns the address1.
169
         */
170
        @Override
171
        public String getAddress1() {
172
                return address1;
1✔
173
        }
174
        
175
        /**
176
         * @param address1 The address1 to set.
177
         */
178
        @Override
179
        public void setAddress1(String address1) {
180
                this.address1 = address1;
1✔
181
        }
1✔
182
        
183
        /**
184
         * @return Returns the address2.
185
         */
186
        @Override
187
        public String getAddress2() {
188
                return address2;
1✔
189
        }
190
        
191
        /**
192
         * @param address2 The address2 to set.
193
         */
194
        @Override
195
        public void setAddress2(String address2) {
196
                this.address2 = address2;
1✔
197
        }
1✔
198
        
199
        /**
200
         * @return Returns the cityVillage.
201
         */
202
        @Override
203
        public String getCityVillage() {
204
                return cityVillage;
1✔
205
        }
206
        
207
        /**
208
         * @param cityVillage The cityVillage to set.
209
         */
210
        @Override
211
        public void setCityVillage(String cityVillage) {
212
                this.cityVillage = cityVillage;
1✔
213
        }
1✔
214
        
215
        /**
216
         * @return Returns the country.
217
         */
218
        @Override
219
        public String getCountry() {
220
                return country;
1✔
221
        }
222
        
223
        /**
224
         * @param country The country to set.
225
         */
226
        @Override
227
        public void setCountry(String country) {
228
                this.country = country;
1✔
229
        }
1✔
230
        
231
        /**
232
         * @return Returns the latitude.
233
         */
234
        @Override
235
        public String getLatitude() {
236
                return latitude;
1✔
237
        }
238
        
239
        /**
240
         * @param latitude The latitude to set.
241
         */
242
        @Override
243
        public void setLatitude(String latitude) {
244
                this.latitude = latitude;
1✔
245
        }
1✔
246
        
247
        /**
248
         * @return Returns the locationId.
249
         */
250
        public Integer getLocationId() {
251
                return locationId;
1✔
252
        }
253
        
254
        /**
255
         * @param locationId The locationId to set.
256
         */
257
        public void setLocationId(Integer locationId) {
258
                this.locationId = locationId;
×
259
        }
×
260
        
261
        /**
262
         * @return Returns the longitude.
263
         */
264
        @Override
265
        public String getLongitude() {
266
                return longitude;
1✔
267
        }
268
        
269
        /**
270
         * @param longitude The longitude to set.
271
         */
272
        @Override
273
        public void setLongitude(String longitude) {
274
                this.longitude = longitude;
1✔
275
        }
1✔
276
        
277
        /**
278
         * @return Returns the postalCode.
279
         */
280
        @Override
281
        public String getPostalCode() {
282
                return postalCode;
1✔
283
        }
284
        
285
        /**
286
         * @param postalCode The postalCode to set.
287
         */
288
        @Override
289
        public void setPostalCode(String postalCode) {
290
                this.postalCode = postalCode;
1✔
291
        }
1✔
292
        
293
        /**
294
         * @return Returns the stateProvince.
295
         */
296
        @Override
297
        public String getStateProvince() {
298
                return stateProvince;
1✔
299
        }
300
        
301
        /**
302
         * @param stateProvince The stateProvince to set.
303
         */
304
        @Override
305
        public void setStateProvince(String stateProvince) {
306
                this.stateProvince = stateProvince;
1✔
307
        }
1✔
308
        
309
        @Override
310
        public String toString() {
311
                if (getName() != null) {
1✔
312
                        return getName();
1✔
313
                }
314
                if (getId() != null) {
1✔
315
                        return getId().toString();
×
316
                }
317
                return "";
1✔
318
        }
319
        
320
        /**
321
         * @return Returns the countyDistrict.
322
         */
323
        @Override
324
        public String getCountyDistrict() {
325
                return countyDistrict;
1✔
326
        }
327
        
328
        /**
329
         * @param countyDistrict The countyDistrict to set.
330
         */
331
        @Override
332
        public void setCountyDistrict(String countyDistrict) {
333
                this.countyDistrict = countyDistrict;
1✔
334
        }
1✔
335

336
        /**
337
         * @return Returns the code indicating the type of location this is
338
         * @since 2.5.0
339
         */
340
        public Concept getType() {
341
                return type;
1✔
342
        }
343
        
344
        /**
345
         * @param type The Concept for the type of location this is
346
         * @since 2.5.0
347
         */
348
        public void setType(Concept type) {
349
                this.type = type;
1✔
350
        }
1✔
351
        
352
        /**
353
         * @see org.openmrs.Attributable#findPossibleValues(java.lang.String)
354
         */
355
        @Override
356
        @Deprecated
357
        public List<Location> findPossibleValues(String searchText) {
358
                try {
359
                        return Context.getLocationService().getLocations(searchText);
×
360
                }
361
                catch (Exception e) {
×
362
                        return Collections.emptyList();
×
363
                }
364
        }
365
        
366
        /**
367
         * @see org.openmrs.Attributable#getPossibleValues()
368
         */
369
        @Override
370
        @Deprecated
371
        public List<Location> getPossibleValues() {
372
                try {
373
                        return Context.getLocationService().getAllLocations();
×
374
                }
375
                catch (Exception e) {
×
376
                        return Collections.emptyList();
×
377
                }
378
        }
379
        
380
        /**
381
         * @see org.openmrs.Attributable#hydrate(java.lang.String)
382
         */
383
        @Override
384
        public Location hydrate(String locationId) {
385
                try {
386
                        return Context.getLocationService().getLocation(Integer.valueOf(locationId));
×
387
                }
388
                catch (Exception e) {
×
389
                        return new Location();
×
390
                }
391
        }
392
        
393
        /**
394
         * @see org.openmrs.Attributable#serialize()
395
         */
396
        @Override
397
        public String serialize() {
398
                if (getLocationId() != null) {
×
399
                        return "" + getLocationId();
×
400
                } else {
401
                        return "";
×
402
                }
403
        }
404
        
405
        /**
406
         * @see org.openmrs.Attributable#getDisplayString()
407
         */
408
        @Override
409
        public String getDisplayString() {
410
                return getName();
×
411
        }
412
        
413
        /**
414
         * @return Returns the parentLocation.
415
         * @since 1.5
416
         */
417
        public Location getParentLocation() {
418
                return parentLocation;
1✔
419
        }
420
        
421
        /**
422
         * @param parentLocationId The parentLocation to set.
423
         * @since 1.5
424
         */
425
        public void setParentLocation(Location parentLocationId) {
426
                this.parentLocation = parentLocationId;
1✔
427
        }
1✔
428
        
429
        /**
430
         * @return Returns the childLocations.
431
         * @since 1.5
432
         */
433
        public Set<Location> getChildLocations() {
434
                return childLocations;
1✔
435
        }
436
        
437
        /**
438
         * Returns all childLocations where child.locationId = this.locationId.
439
         *
440
         * @param includeRetired specifies whether or not to include voided childLocations
441
         * @return Returns a Set&lt;Location&gt; of all the childLocations.
442
         * @since 1.5
443
         * <strong>Should</strong> return a set of locations
444
         */
445
        public Set<Location> getChildLocations(boolean includeRetired) {
446
                Set<Location> ret = new HashSet<>();
×
447
                if (includeRetired) {
×
448
                        ret = getChildLocations();
×
449
                } else if (getChildLocations() != null) {
×
450
                        for (Location l : getChildLocations()) {
×
451
                                if (!l.getRetired()) {
×
452
                                        ret.add(l);
×
453
                                }
454
                        }
×
455
                }
456
                return ret;
×
457
        }
458
        
459
        /**
460
         * Returns the descendant locations.
461
         *
462
         * @param includeRetired specifies whether or not to include voided childLocations
463
         * @return Returns a Set&lt;Location&gt; of the descendant location.
464
         * @since 1.10
465
         * @deprecated since 2.8.7 in favor of {@link LocationService#getDescendantLocations(Location, boolean)}
466
         */
467
        @Deprecated
468
        public Set<Location> getDescendantLocations(boolean includeRetired) {
UNCOV
469
                Set<Location> result = new HashSet<>();
×
470
                
UNCOV
471
                for (Location childLocation : getChildLocations()) {
×
UNCOV
472
                        if (!childLocation.getRetired() || includeRetired) {
×
UNCOV
473
                                result.add(childLocation);
×
UNCOV
474
                                result.addAll(childLocation.getDescendantLocations(includeRetired));
×
475
                        }
UNCOV
476
                }
×
UNCOV
477
                return result;
×
478
        }
479
        
480
        /**
481
         * @param childLocations The childLocations to set.
482
         * @since 1.5
483
         */
484
        public void setChildLocations(Set<Location> childLocations) {
UNCOV
485
                this.childLocations = childLocations;
×
UNCOV
486
        }
×
487
        
488
        /**
489
         * @param child The child location to add.
490
         * @since 1.5
491
         * <strong>Should</strong> return null given null parameter
492
         * <strong>Should</strong> throw APIException given same object as child
493
         * <strong>Should</strong> throw APIException if child already in hierarchy
494
         */
495
        public void addChildLocation(Location child) {
496
                if (child == null) {
1✔
497
                        return;
×
498
                }
499
                
500
                if (getChildLocations() == null) {
1✔
501
                        childLocations = new HashSet<>();
1✔
502
                }
503
                
504
                if (child.equals(this)) {
1✔
505
                        throw new APIException("Location.cannot.be.its.own.child", (Object[]) null);
×
506
                }
507
                
508
                // Traverse all the way up (down?) to the root, then check whether the child is already
509
                // anywhere in the tree
510
                Location root = this;
1✔
511
                while (root.getParentLocation() != null) {
1✔
512
                        root = root.getParentLocation();
1✔
513
                }
514
                
515
                if (isInHierarchy(child, root)) {
1✔
516
                        throw new APIException("Location.hierarchy.loop", new Object[] { child, this });
×
517
                }
518
                
519
                child.setParentLocation(this);
1✔
520
                childLocations.add(child);
1✔
521
        }
1✔
522
        
523
        /**
524
         * Checks whether 'location' is a member of the tree starting at 'root'.
525
         *
526
         * @param location The location to be tested.
527
         * @param root Location node from which to start the testing (down in the hierarchy).
528
         * @since 1.5
529
         * <strong>Should</strong> return false given any null parameter
530
         * <strong>Should</strong> return true given same object in both parameters
531
         * <strong>Should</strong> return true given location that is already somewhere in hierarchy
532
         * <strong>Should</strong> return false given location that is not in hierarchy
533
         * <strong>Should</strong> should find location in hierarchy
534
         */
535
        public static Boolean isInHierarchy(Location location, Location root) {
536
                if (root == null) {
1✔
537
                        return false;
×
538
                }
539
                while (true) {
540
                        if (location == null) {
1✔
541
                                return false;
1✔
542
                        } else if (root.equals(location)) {
1✔
543
                                return true;
1✔
544
                        }
545
                        location = location.getParentLocation();
1✔
546
                }
547
        }
548
        
549
        /**
550
         * @param child The child location to remove.
551
         * @since 1.5
552
         */
553
        public void removeChildLocation(Location child) {
554
                if (getChildLocations() != null) {
1✔
555
                        childLocations.remove(child);
1✔
556
                }
557
        }
1✔
558
        
559
        /**
560
         * @return Returns the tags which have been attached to this Location.
561
         * @since 1.5
562
         */
563
        public Set<LocationTag> getTags() {
564
                return tags;
1✔
565
        }
566
        
567
        /**
568
         * Set the tags which are attached to this Location.
569
         *
570
         * @param tags The tags to set.
571
         * @since 1.5
572
         */
573
        public void setTags(Set<LocationTag> tags) {
574
                this.tags = tags;
×
575
        }
×
576
        
577
        /**
578
         * Attaches a tag to the Location.
579
         *
580
         * @param tag The tag to add.
581
         * @since 1.5
582
         */
583
        public void addTag(LocationTag tag) {
584
                if (getTags() == null) {
1✔
585
                        tags = new HashSet<>();
1✔
586
                }
587
                if (tag != null && !tags.contains(tag)) {
1✔
588
                        tags.add(tag);
1✔
589
                }
590
        }
1✔
591
        
592
        /**
593
         * Remove the tag from the Location.
594
         *
595
         * @param tag The tag to remove.
596
         * @since 1.5
597
         */
598
        public void removeTag(LocationTag tag) {
599
                if (getTags() != null) {
1✔
600
                        tags.remove(tag);
1✔
601
                }
602
        }
1✔
603
        
604
        /**
605
         * Checks whether the Location has a particular tag.
606
         *
607
         * @param tagToFind the string of the tag for which to check
608
         * @return true if the tags include the specified tag, false otherwise
609
         * @since 1.5
610
         * <strong>Should</strong> not fail given null parameter
611
         * <strong>Should</strong> return false given empty string parameter
612
         */
613
        public Boolean hasTag(String tagToFind) {
614
                if (tagToFind != null && getTags() != null) {
×
615
                        for (LocationTag locTag : getTags()) {
×
616
                                if (locTag.getName().equals(tagToFind)) {
×
617
                                        return true;
×
618
                                }
619
                        }
×
620
                }
621
                
622
                return false;
×
623
        }
624
        
625
        /**
626
         * @since 1.8
627
         * @return the address3
628
         */
629
        @Override
630
        public String getAddress3() {
631
                return address3;
1✔
632
        }
633
        
634
        /**
635
         * @since 1.8
636
         * @param address3 the address3 to set
637
         */
638
        @Override
639
        public void setAddress3(String address3) {
640
                this.address3 = address3;
1✔
641
        }
1✔
642
        
643
        /**
644
         * @since 1.8
645
         * @return the address4
646
         */
647
        @Override
648
        public String getAddress4() {
649
                return address4;
1✔
650
        }
651
        
652
        /**
653
         * @since 1.8
654
         * @param address4 the address4 to set
655
         */
656
        @Override
657
        public void setAddress4(String address4) {
658
                this.address4 = address4;
1✔
659
        }
1✔
660
        
661
        /**
662
         * @since 1.8
663
         * @return the address6
664
         */
665
        @Override
666
        public String getAddress6() {
667
                return address6;
1✔
668
        }
669
        
670
        /**
671
         * @since 1.8
672
         * @param address6 the address6 to set
673
         */
674
        @Override
675
        public void setAddress6(String address6) {
676
                this.address6 = address6;
1✔
677
        }
1✔
678
        
679
        /**
680
         * @since 1.8
681
         * @return the address5
682
         */
683
        @Override
684
        public String getAddress5() {
685
                return address5;
1✔
686
        }
687
        
688
        /**
689
         * @since 1.8
690
         * @param address5 the address5 to set
691
         */
692
        @Override
693
        public void setAddress5(String address5) {
694
                this.address5 = address5;
1✔
695
        }
1✔
696
        
697
        /**
698
         * @since 1.5
699
         * @see org.openmrs.OpenmrsObject#getId()
700
         */
701
        @Override
702
        public Integer getId() {
703
                
704
                return getLocationId();
1✔
705
        }
706
        
707
        /**
708
         * @since 1.5
709
         * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
710
         */
711
        @Override
712
        public void setId(Integer id) {
713
                setLocationId(id);
×
714
                
715
        }
×
716

717
        /**
718
         * {@inheritDoc}
719
         */
720
        @Override
721
        public String getAddress7() {
722
                return address7;
1✔
723
        }
724

725
        /**
726
         * {@inheritDoc}
727
         */
728
        @Override
729
        public void setAddress7(String address7) {
730
                this.address7 = address7;
1✔
731
        }
1✔
732

733
        /**
734
         * {@inheritDoc}
735
         */
736
        @Override
737
        public String getAddress8() {
738
                return address8;
1✔
739
        }
740

741
        /**
742
         * {@inheritDoc}
743
         */
744
        @Override
745
        public void setAddress8(String address8) {
746
                this.address8 = address8;
1✔
747
        }
1✔
748

749
        /**
750
         * {@inheritDoc}
751
         */
752
        @Override
753
        public String getAddress9() {
754
                return address9;
1✔
755
        }
756

757
        /**
758
         * {@inheritDoc}
759
         */
760
        @Override
761
        public void setAddress9(String address9) {
762
                this.address9 = address9;
1✔
763
        }
1✔
764

765
        /**
766
         * {@inheritDoc}
767
         */
768
        @Override
769
        public String getAddress10() {
770
                return address10;
1✔
771
        }
772

773
        /**
774
         * {@inheritDoc}
775
         */
776
        @Override
777
        public void setAddress10(String address10) {
778
                this.address10 = address10;
1✔
779
        }
1✔
780

781
        /**
782
         * {@inheritDoc}
783
         */
784
        @Override
785
        public String getAddress11() {
786
                return address11;
1✔
787
        }
788

789
        /**
790
         * {@inheritDoc}
791
         */
792
        @Override
793
        public void setAddress11(String address11) {
794
                this.address11 = address11;
1✔
795
        }
1✔
796

797
        /**
798
         * {@inheritDoc}
799
         */
800
        @Override
801
        public String getAddress12() {
802
                return address12;
1✔
803
        }
804

805
        /**
806
         * {@inheritDoc}
807
         */
808
        @Override
809
        public void setAddress12(String address12) {
810
                this.address12 = address12;
1✔
811
        }
1✔
812

813
        /**
814
         * {@inheritDoc}
815
         */
816
        @Override
817
        public String getAddress13() {
818
                return address13;
1✔
819
        }
820

821
        /**
822
         * {@inheritDoc}
823
         */
824
        @Override
825
        public void setAddress13(String address13) {
826
                this.address13 = address13;
1✔
827
        }
1✔
828

829
        /**
830
         * {@inheritDoc}
831
         */
832
        @Override
833
        public String getAddress14() {
834
                return address14;
1✔
835
        }
836

837
        /**
838
         * {@inheritDoc}
839
         */
840
        @Override
841
        public void setAddress14(String address14) {
842
                this.address14 = address14;
1✔
843
        }
1✔
844

845
        /**
846
         * {@inheritDoc}
847
         */
848
        @Override
849
        public String getAddress15() {
850
                return address15;
1✔
851
        }
852

853
        /**
854
         * {@inheritDoc}
855
         */
856
        @Override
857
        public void setAddress15(String address15) {
858
                this.address15 = address15;
1✔
859
        }
1✔
860
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc