Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit b06f8b3

Browse files
Merge pull request SORMAS-Foundation#2891 from hzi-braunschweig/feature-2746-Person_address_refinement_Part_2
Feature 2746 person address refinement part 2
2 parents a08bcce + 4a96bd9 commit b06f8b3

24 files changed

Lines changed: 758 additions & 96 deletions

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ public ADO saveAndSnapshot(ADO ado) throws DaoException {
377377
AbstractDomainObject embeddedAdo = (AbstractDomainObject) property.getReadMethod().invoke(ado);
378378

379379
AbstractDomainObject embeddedAdoSnapshot = null;
380-
if (parentProperty.equals(property.getName())) {
380+
if (parentProperty.equals(property.getName()) || property.getReadMethod().isAnnotationPresent(JoinTableReference.class)) {
381381

382382
// ignore parent property
383383
if (!withSnapshot)
@@ -441,7 +441,14 @@ public void saveCollectionWithSnapshot(Collection<ADO> existingCollection, Colle
441441
try {
442442
// get the setter
443443
String parentPropertyName = getAdoClass().getAnnotation(EmbeddedAdo.class).parentAccessor();
444-
String methodName = "set" + parentPropertyName.substring(0, 1).toUpperCase() + parentPropertyName.substring(1);
444+
String methodName;
445+
if (StringUtils.isNotBlank(parentPropertyName)) {
446+
methodName = "set" + parentPropertyName.substring(0, 1).toUpperCase() + parentPropertyName.substring(1);
447+
} else {
448+
// Explicitely used for location-person relation because locations don't have a distinct parent accessor;
449+
// This only works if the field has the same name as its class (e.g. Person person)
450+
methodName = "set" + parent.getClass().getSimpleName().substring(0, 1).toUpperCase() + parent.getClass().getSimpleName().substring(1);
451+
}
445452
Method parentSetter = getAdoClass().getMethod(methodName, parent.getClass());
446453

447454
// save remaining
@@ -502,7 +509,7 @@ public ADO deleteWithSnapshot(ADO ado) throws DaoException {
502509
AbstractDomainObject embeddedAdo = (AbstractDomainObject) property.getReadMethod().invoke(ado);
503510

504511
AbstractDomainObject embeddedAdoSnapshot;
505-
if (parentProperty.equals(property.getName())) {
512+
if (parentProperty.equals(property.getName()) || property.getReadMethod().isAnnotationPresent(JoinTableReference.class)) {
506513

507514
// ignore parent property
508515
if (!snapshotNeeded)
@@ -608,6 +615,7 @@ public ADO mergeOrCreate(ADO source) throws DaoException {
608615
// ignore some types and specific properties
609616
if (!AdoPropertyHelper.isModifiableProperty(property)
610617
|| parentProperty.equals(property.getName())
618+
|| property.getReadMethod().isAnnotationPresent(JoinTableReference.class)
611619
|| Case.COMPLETENESS.equals(property.getName()))
612620
continue;
613621

@@ -788,7 +796,15 @@ private void mergeCollection(Collection<AbstractDomainObject> existingCollection
788796
if (parentSetter == null) {
789797
// get the setter
790798
String parentPropertyName = resultElement.getClass().getAnnotation(EmbeddedAdo.class).parentAccessor();
791-
String methodName = "set" + parentPropertyName.substring(0, 1).toUpperCase() + parentPropertyName.substring(1);
799+
String methodName;
800+
if (StringUtils.isNotBlank(parentPropertyName)) {
801+
methodName = "set" + parentPropertyName.substring(0, 1).toUpperCase() + parentPropertyName.substring(1);
802+
} else {
803+
// Explicitely used for location-person relation because locations don't have a distinct parent accessor;
804+
// This only works if the field has the same name as its class (e.g. Person person)
805+
methodName = "set" + parent.getClass().getSimpleName().substring(0, 1).toUpperCase()
806+
+ parent.getClass().getSimpleName().substring(1);
807+
}
792808
parentSetter = resultElement.getClass().getMethod(methodName, parent.getClass());
793809
}
794810

@@ -879,7 +895,7 @@ public void accept(ADO ado) throws DaoException {
879895
PropertyDescriptor property = propertyIterator.next();
880896

881897
// ignore parent property
882-
if (parentProperty.equals(property.getName())) {
898+
if (parentProperty.equals(property.getName()) || property.getReadMethod().isAnnotationPresent(JoinTableReference.class)) {
883899
continue;
884900
}
885901

@@ -929,7 +945,7 @@ public void deleteCascade(ADO ado) throws SQLException {
929945
PropertyDescriptor property = propertyIterator.next();
930946

931947
// ignore parent property
932-
if (parentProperty.equals(property.getName()))
948+
if (parentProperty.equals(property.getName()) || property.getReadMethod().isAnnotationPresent(JoinTableReference.class))
933949
continue;
934950

935951
// get embedded
@@ -1039,7 +1055,7 @@ public ADO build() {
10391055
PropertyDescriptor property = propertyIterator.next();
10401056

10411057
// ignore parent property
1042-
if (parentProperty.equals(property.getName()))
1058+
if (parentProperty.equals(property.getName()) || property.getReadMethod().isAnnotationPresent(JoinTableReference.class))
10431059
continue;
10441060

10451061
// build embedded

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
128128
public static final String DATABASE_NAME = "sormas.db";
129129
// any time you make changes to your database objects, you may have to increase the database version
130130

131-
public static final int DATABASE_VERSION = 226;
131+
public static final int DATABASE_VERSION = 227;
132132

133133
private static DatabaseHelper instance = null;
134134

@@ -1578,6 +1578,13 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int
15781578
getDao(Case.class).executeRaw("ALTER TABLE contacts ADD COLUMN quarantineOfficialOrderSent SMALLINT DEFAULT 0;");
15791579
getDao(Case.class).executeRaw("ALTER TABLE contacts ADD COLUMN quarantineOfficialOrderSentDate timestamp;");
15801580

1581+
case 226:
1582+
currentVersion = 226;
1583+
// Re-synchronize persons to retrieve new addresses
1584+
getDao(Location.class).executeRaw("ALTER TABLE location ADD COLUMN person_id bigint REFERENCES person(id);");
1585+
getDao(Person.class).executeRaw("UPDATE person SET changeDate = 0 WHERE changeDate IS NOT NULL;");
1586+
getDao(Location.class).executeRaw("UPDATE location SET changeDate = 0 WHERE changeDate IS NOT NULL;");
1587+
15811588
// ATTENTION: break should only be done after last version
15821589
break;
15831590
default:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package de.symeda.sormas.app.backend.common;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
/**
9+
* Explicitely used for person-location association because location is an embedded entity without a
10+
* parent accessor, but has a many-to-one relation with persons; this makes sure that the same logic
11+
* that would be applied to a field of the distinct parent accessor is also applied to the field
12+
* annotated with this annotation.
13+
*/
14+
@Target({
15+
ElementType.METHOD })
16+
@Retention(RetentionPolicy.RUNTIME)
17+
public @interface JoinTableReference {
18+
}

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/hospitalization/Hospitalization.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public class Hospitalization extends AbstractDomainObject {
6767
@DatabaseField(dataType = DataType.DATE_LONG)
6868
private Date intensiveCareUnitEnd;
6969
// just for reference, not persisted in DB
70-
private List<PreviousHospitalization> previousHospitalizations = new ArrayList<PreviousHospitalization>();
70+
private List<PreviousHospitalization> previousHospitalizations = new ArrayList<>();
7171

7272
public Date getAdmissionDate() {
7373
return admissionDate;

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/Location.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import de.symeda.sormas.api.person.PersonAddressType;
3333
import de.symeda.sormas.api.utils.DataHelper;
3434
import de.symeda.sormas.app.backend.common.EmbeddedAdo;
35+
import de.symeda.sormas.app.backend.common.JoinTableReference;
3536
import de.symeda.sormas.app.backend.common.PseudonymizableAdo;
37+
import de.symeda.sormas.app.backend.person.Person;
3638
import de.symeda.sormas.app.backend.region.Community;
3739
import de.symeda.sormas.app.backend.region.District;
3840
import de.symeda.sormas.app.backend.region.Region;
@@ -47,6 +49,7 @@ public class Location extends PseudonymizableAdo {
4749
public static final String TABLE_NAME = "location";
4850
public static final String I18N_PREFIX = "Location";
4951
public static final String COMMUNITY = "community";
52+
public static final String PERSON = "person";
5053

5154
@Column(length = COLUMN_LENGTH_DEFAULT)
5255
private String details;
@@ -82,6 +85,14 @@ public class Location extends PseudonymizableAdo {
8285
@Column(length = COLUMN_LENGTH_DEFAULT)
8386
private String addressTypeDetails;
8487

88+
/**
89+
* Dirty fix for person-location association; doing this with a JoinTable is not
90+
* easy in SQLite; only locations that are part of the addresses field of a person
91+
* have this association.
92+
*/
93+
@DatabaseField(foreign = true, foreignAutoRefresh = true)
94+
private Person person;
95+
8596
@Bindable
8697
public String getDetails() {
8798
return details;
@@ -199,6 +210,15 @@ public void setAddressTypeDetails(String addressTypeDetails) {
199210
this.addressTypeDetails = addressTypeDetails;
200211
}
201212

213+
@JoinTableReference
214+
public Person getPerson() {
215+
return person;
216+
}
217+
218+
public void setPerson(Person person) {
219+
this.person = person;
220+
}
221+
202222
public String getCompleteString() {
203223

204224
StringBuilder sb = new StringBuilder();
@@ -326,4 +346,5 @@ public Float getLatLonAccuracy() {
326346
public void setLatLonAccuracy(Float latLonAccuracy) {
327347
this.latLonAccuracy = latLonAccuracy;
328348
}
349+
329350
}

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/location/LocationDao.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616
package de.symeda.sormas.app.backend.location;
1717

1818
import java.sql.SQLException;
19+
import java.util.List;
1920

2021
import com.j256.ormlite.dao.Dao;
2122

2223
import de.symeda.sormas.app.backend.common.AbstractAdoDao;
24+
import de.symeda.sormas.app.backend.epidata.EpiDataBurial;
25+
import de.symeda.sormas.app.backend.person.Person;
2326

2427
/**
2528
* Created by Martin Wahnschaffe on 22.07.2016.
@@ -30,6 +33,13 @@ public LocationDao(Dao<Location, Long> innerDao) throws SQLException {
3033
super(innerDao);
3134
}
3235

36+
public List<Location> getByPerson(Person person) {
37+
if (person.isSnapshot()) {
38+
return querySnapshotsForEq(Location.PERSON + "_id", person, Location.CHANGE_DATE, false);
39+
}
40+
return queryForEq(Location.PERSON + "_id", person, Location.CHANGE_DATE, false);
41+
}
42+
3343
@Override
3444
protected Class<Location> getAdoClass() {
3545
return Location.class;

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/person/Person.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@
1717

1818
import static de.symeda.sormas.api.EntityDto.COLUMN_LENGTH_DEFAULT;
1919

20+
import java.util.ArrayList;
2021
import java.util.Date;
22+
import java.util.List;
23+
import java.util.Set;
2124

25+
import javax.persistence.CascadeType;
2226
import javax.persistence.Column;
2327
import javax.persistence.Entity;
2428
import javax.persistence.EnumType;
2529
import javax.persistence.Enumerated;
30+
import javax.persistence.FetchType;
31+
import javax.persistence.JoinColumn;
32+
import javax.persistence.JoinTable;
33+
import javax.persistence.OneToMany;
34+
import javax.persistence.Transient;
2635

2736
import com.j256.ormlite.field.DataType;
2837
import com.j256.ormlite.field.DatabaseField;
@@ -174,6 +183,8 @@ public class Person extends PseudonymizableAdo {
174183
@Column
175184
private String nationalHealthId;
176185

186+
private List<Location> addresses = new ArrayList<>();
187+
177188
public Person() {
178189
}
179190

@@ -576,4 +587,12 @@ public FacilityType getOccupationFacilityType() {
576587
public void setOccupationFacilityType(FacilityType occupationFacilityType) {
577588
this.occupationFacilityType = occupationFacilityType;
578589
}
590+
591+
public List<Location> getAddresses() {
592+
return addresses;
593+
}
594+
595+
public void setAddresses(List<Location> addresses) {
596+
this.addresses = addresses;
597+
}
579598
}

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/person/PersonDao.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import de.symeda.sormas.app.backend.common.AbstractAdoDao;
3333
import de.symeda.sormas.app.backend.common.AbstractDomainObject;
3434
import de.symeda.sormas.app.backend.common.DaoException;
35+
import de.symeda.sormas.app.backend.common.DatabaseHelper;
3536
import de.symeda.sormas.app.backend.location.Location;
3637

3738
public class PersonDao extends AbstractAdoDao<Person> {
@@ -88,6 +89,33 @@ public List<PersonNameDto> getRelevantPersonNames(PersonSimilarityCriteria simil
8889
}
8990
}
9091

92+
@Override
93+
public Person queryUuid(String uuid) {
94+
Person person = super.queryUuid(uuid);
95+
if (person != null) {
96+
initLocations(person);
97+
}
98+
return person;
99+
}
100+
101+
@Override
102+
public Person queryForId(Long id) {
103+
Person person = super.queryForId(id);
104+
if (person != null) {
105+
initLocations(person);
106+
}
107+
return person;
108+
}
109+
110+
@Override
111+
public Person querySnapshotByUuid(String uuid) {
112+
Person person = super.querySnapshotByUuid(uuid);
113+
if (person != null) {
114+
initLocations(person);
115+
}
116+
return person;
117+
}
118+
91119
@Override
92120
public Date getLatestChangeDate() {
93121
Date date = super.getLatestChangeDate();
@@ -108,7 +136,12 @@ public Person saveAndSnapshot(final Person person) throws DaoException {
108136

109137
final Person existingPerson = queryUuid(person.getUuid());
110138
onPersonChanged(existingPerson, person);
111-
return super.saveAndSnapshot(person);
139+
140+
Person snapshot = super.saveAndSnapshot(person);
141+
DatabaseHelper.getLocationDao()
142+
.saveCollectionWithSnapshot(DatabaseHelper.getLocationDao().getByPerson(person), person.getAddresses(), person);
143+
144+
return snapshot;
112145
}
113146

114147
private void onPersonChanged(Person existingPerson, Person changedPerson) {
@@ -124,4 +157,9 @@ private void onPersonChanged(Person existingPerson, Person changedPerson) {
124157
}
125158
}
126159
}
160+
161+
public Person initLocations(Person person) {
162+
person.setAddresses(DatabaseHelper.getLocationDao().getByPerson(person));
163+
return person;
164+
}
127165
}

sormas-app/app/src/main/java/de/symeda/sormas/app/backend/person/PersonDtoHelper.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,19 @@
1515

1616
package de.symeda.sormas.app.backend.person;
1717

18+
import java.util.ArrayList;
1819
import java.util.List;
1920

2021
import de.symeda.sormas.api.PushResult;
22+
import de.symeda.sormas.api.hospitalization.PreviousHospitalizationDto;
23+
import de.symeda.sormas.api.location.LocationDto;
2124
import de.symeda.sormas.api.person.PersonDto;
2225
import de.symeda.sormas.api.person.PersonReferenceDto;
2326
import de.symeda.sormas.app.backend.common.AdoDtoHelper;
2427
import de.symeda.sormas.app.backend.common.DatabaseHelper;
2528
import de.symeda.sormas.app.backend.facility.Facility;
2629
import de.symeda.sormas.app.backend.facility.FacilityDtoHelper;
30+
import de.symeda.sormas.app.backend.hospitalization.PreviousHospitalization;
2731
import de.symeda.sormas.app.backend.location.Location;
2832
import de.symeda.sormas.app.backend.location.LocationDtoHelper;
2933
import de.symeda.sormas.app.backend.region.Community;
@@ -125,6 +129,16 @@ public void fillInnerFromDto(Person target, PersonDto source) {
125129
target.setPseudonymized(source.isPseudonymized());
126130
target.setOccupationFacilityType(source.getOccupationFacilityType());
127131
target.setPlaceOfBirthFacilityType(source.getPlaceOfBirthFacilityType());
132+
133+
List<Location> addresses = new ArrayList<>();
134+
if (!source.getAddresses().isEmpty()) {
135+
for (LocationDto locationDto : source.getAddresses()) {
136+
Location location = locationHelper.fillOrCreateFromDto(null, locationDto);
137+
location.setPerson(target);
138+
addresses.add(location);
139+
}
140+
}
141+
target.setAddresses(addresses);
128142
}
129143

130144
@Override
@@ -231,6 +245,15 @@ public void fillInnerFromAdo(PersonDto target, Person source) {
231245
target.setPseudonymized(source.isPseudonymized());
232246
target.setOccupationFacilityType(source.getOccupationFacilityType());
233247
target.setPlaceOfBirthFacilityType(source.getPlaceOfBirthFacilityType());
248+
249+
List<LocationDto> locationDtos = new ArrayList<>();
250+
// Necessary because the person is synchronized independently
251+
DatabaseHelper.getPersonDao().initLocations(source);
252+
for (Location location : source.getAddresses()) {
253+
LocationDto locationDto = locationHelper.adoToDto(location);
254+
locationDtos.add(locationDto);
255+
}
256+
target.setAddresses(locationDtos);
234257
}
235258

236259
public static PersonReferenceDto toReferenceDto(Person ado) {

0 commit comments

Comments
 (0)