Work on multitenancy

This commit is contained in:
jamesagnew 2020-03-27 09:22:00 -04:00
parent ec6fe70acb
commit 9df4c58122
5 changed files with 66 additions and 43 deletions

View File

@ -25,8 +25,3 @@
has been replaced with an equivalent `FhirContext.newFhirPath()`. The FhirPath expression language was initially
called FluentPath before being renamed, so this change brings HAPI FHIR inline with the correct naming.
"
- item:
type: change
title: "The JPA server now shared a single set of tags for all versions of a resource, bringing it in line with the
functional description in the FHIR specification. This means that it is no longer possible to modify the tags for
a specific version of a resource, and also causes significant performance improvements in some cases."

View File

@ -28,6 +28,7 @@ import org.junit.Test;
import javax.servlet.ServletException;
import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@ -36,16 +37,19 @@ import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.when;
public class MultitenantR4Test extends BaseJpaR4SystemTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MultitenantR4Test.class);
private MyInterceptor myTenantInterceptor;
@After
public void after() {
myDaoConfig.setMultiTenancyEnabled(new DaoConfig().isMultiTenancyEnabled());
myInterceptorRegistry.unregisterInterceptorsIf(t -> t instanceof MyInterceptor);
myInterceptor = null;
}
@Override
@ -74,56 +78,84 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
public void testCreateResourceWithTenant() {
createUniqueCompositeSp();
int expectId = 3;
LocalDate expectDate = LocalDate.of(2020, Month.JANUARY, 14);
myInterceptorRegistry.registerInterceptor(new MyInterceptor(new TenantId(expectId, expectDate)));
addTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
addTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
Organization org = new Organization();
org.setName("org");
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
Patient p = new Patient();
p.getMeta().addTag("http://system", "code", "diisplay");
p.addName().setFamily("FAM");
p.addIdentifier().setSystem("system").setValue("value");
p.setBirthDate(new Date());
p.getManagingOrganization().setReferenceElement(orgId);
Long patientId = myPatientDao.create(p).getId().getIdPartAsLong();
when(mySrd.getRequestId()).thenReturn("REQUEST_ID");
Long patientId = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
runInTransaction(() -> {
// HFJ_RESOURCE
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
assertEquals(expectId, resourceTable.getTenantId().getTenantId().intValue());
assertEquals(expectDate, resourceTable.getTenantId().getTenantDate());
assertEquals(3, resourceTable.getTenantId().getTenantId().intValue());
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), resourceTable.getTenantId().getTenantDate());
resourceTable.getProfile()
// HFJ_RES_VER
ResourceHistoryTable version = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 1L);
assertEquals(expectId, version.getTenantId().getTenantId().intValue());
assertEquals(expectDate, version.getTenantId().getTenantDate());
assertEquals(3, version.getTenantId().getTenantId().intValue());
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), version.getTenantId().getTenantDate());
// HFJ_SPIDX_STRING
List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId);
ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * ")));
assertEquals(10, strings.size());
assertEquals(expectId, strings.get(0).getTenantId().getTenantId().intValue());
assertEquals(expectDate, strings.get(0).getTenantId().getTenantDate());
assertEquals(3, strings.get(0).getTenantId().getTenantId().intValue());
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), strings.get(0).getTenantId().getTenantDate());
// HFJ_RES_LINK
List<ResourceLink> resourceLinks = myResourceLinkDao.findAllForResourceId(patientId);
assertEquals(1, resourceLinks.size());
assertEquals(expectId, resourceLinks.get(0).getTenantId().getTenantId().intValue());
assertEquals(expectDate, resourceLinks.get(0).getTenantId().getTenantDate());
assertEquals(3, resourceLinks.get(0).getTenantId().getTenantId().intValue());
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), resourceLinks.get(0).getTenantId().getTenantDate());
// HFJ_RES_PARAM_PRESENT
List<SearchParamPresent> presents = mySearchParamPresentDao.findAllForResource(resourceTable);
assertEquals(3, presents.size());
assertEquals(expectId, presents.get(0).getTenantId().getTenantId().intValue());
assertEquals(expectDate, presents.get(0).getTenantId().getTenantDate());
assertEquals(3, presents.get(0).getTenantId().getTenantId().intValue());
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), presents.get(0).getTenantId().getTenantDate());
// HFJ_IDX_CMP_STRING_UNIQ
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceId(patientId);
assertEquals(3, uniques.size());
assertEquals(expectId, uniques.get(0).getTenantId().getTenantId().intValue());
assertEquals(expectDate, uniques.get(0).getTenantId().getTenantDate());
assertEquals(3, uniques.get(0).getTenantId().getTenantId().intValue());
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), uniques.get(0).getTenantId().getTenantDate());
});
}
@Test
public void testUpdateResourceWithTenant() {
createUniqueCompositeSp();
addTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
Patient p = new Patient();
p.setActive(true);
Long patientId = myPatientDao.create(p).getId().getIdPartAsLong();
p = new Patient();
p.setId("Patient/" + patientId);
p.setActive(false);
myPatientDao.update(p);
runInTransaction(() -> {
// HFJ_RES_VER
ResourceHistoryTable resVer = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 2);
assertEquals(tenantId, resVer.getTenantId().getTenantId().intValue());
assertEquals(tenantDate, resVer.getTenantId().getTenantDate());
});
}
@ -154,19 +186,27 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
mySearchParamRegistry.forceRefresh();
}
public void addTenant(int theTenantId, LocalDate theTenantDate) {
if (myTenantInterceptor == null) {
myTenantInterceptor = new MyInterceptor();
myInterceptorRegistry.registerInterceptor(myInterceptor);
}
myTenantInterceptor.addTenant(new TenantId(theTenantId, theTenantDate));
}
@Interceptor
public static class MyInterceptor {
private final List<TenantId> myTenantIds;
private final List<TenantId> myTenantIds = new ArrayList<>();
public MyInterceptor(TenantId theTenantId) {
public void addTenant(TenantId theTenantId) {
Validate.notNull(theTenantId);
myTenantIds = Collections.singletonList(theTenantId);
myTenantIds.add(theTenantId);
}
@Hook(Pointcut.STORAGE_TENANT_IDENTIFY_CREATE)
public TenantId tenantIdentifyCreate() {
TenantId retVal = myTenantIds.get(0);
TenantId retVal = myTenantIds.remove(0);
ourLog.info("Returning tenant ID: {}", retVal);
return retVal;
}

View File

@ -57,10 +57,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
init400(); // 20190401 - 20190814
init410(); // 20190815 - 20191014
init420(); // 20191015 - 20200217
init430(); // 20200218 - present
init500(); // 20200218 - present
}
protected void init430() { // 20200218 - present
protected void init500() { // 20200218 - present
Builder version = forVersion(VersionEnum.V4_3_0);
// Eliminate circular dependency.
@ -68,6 +68,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
version.onTable("HFJ_RES_VER").dropColumn("20200218.2", "FORCED_ID_PID");
version.onTable("HFJ_RES_VER").addForeignKey("20200218.3", "FK_RESOURCE_HISTORY_RESOURCE").toColumn("RES_ID").references("HFJ_RESOURCE", "RES_ID");
version.onTable("HFJ_RES_VER").modifyColumn("20200220.1", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
// Add mlutiitenancy
version.onTable("HFJ_RESOURCE").dropColumn("20200327.1", "RES_PROFILE");
}
protected void init420() { // 20191015 - 20200217

View File

@ -60,7 +60,6 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
public class ResourceTable extends BaseHasResource implements Serializable, IBasePersistedResource, IResourceLookup {
public static final int RESTYPE_LEN = 40;
private static final int MAX_LANGUAGE_LENGTH = 20;
private static final int MAX_PROFILE_LENGTH = 200;
private static final long serialVersionUID = 1L;
/**
@ -167,10 +166,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
@OptimisticLock(excluded = true)
private boolean myParamsUriPopulated;
@Column(name = "RES_PROFILE", length = MAX_PROFILE_LENGTH, nullable = true)
@OptimisticLock(excluded = true)
private String myProfile;
// Added in 3.0.0 - Should make this a primitive Boolean at some point
@OptimisticLock(excluded = true)
@Column(name = "SP_CMPSTR_UNIQ_PRESENT")
@ -402,17 +397,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
getParamsUri().addAll(theParamsUri);
}
public String getProfile() {
return myProfile;
}
public void setProfile(String theProfile) {
if (defaultString(theProfile).length() > MAX_PROFILE_LENGTH) {
throw new UnprocessableEntityException("Profile name exceeds maximum length of " + MAX_PROFILE_LENGTH + " chars: " + theProfile);
}
myProfile = theProfile;
}
@Override
public Long getResourceId() {
return getId();

View File

@ -50,6 +50,7 @@ public class ResourceTag extends BaseTag {
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourceId;
@Embedded
private TenantId myTenantId;