Package com.ibm.fhir.schema.app
Class Main
- java.lang.Object
-
- com.ibm.fhir.schema.app.Main
-
public class Main extends Object
Utility app to connect to a database and create/update the IBM FHIR Server schema. The DDL processing is idempotent, with only the necessary changes applied.
This utility also includes an option to exercise the tenant partitioning code.
-
-
Field Summary
Fields Modifier and Type Field Description static String
ADMIN_SCHEMANAME
static String
BATCH_SCHEMANAME
static String
DATA_SCHEMANAME
List<DbType>
MULTITENANT_FEATURE_ENABLED
static String
OAUTH_SCHEMANAME
List<DbType>
PRIVILEGES_FEATURE_ENABLED
List<DbType>
STORED_PROCEDURE_ENABLED
-
Constructor Summary
Constructors Constructor Description Main()
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description void
addProperty(String pair)
Parse the given key=value string and add to the properties being collectedprotected void
addTenantKey()
Add a new tenant key so that we can rotate the values (add a new key, update config files, then remove the old key).protected void
allocateTenant()
Allocate this tenant, creating new partitions if required.protected void
applyDataMigrationForV0010()
Perform the special data migration steps required for the V0010 version of the schemaprotected void
applyDataMigrationForV0014()
protected void
applyModel(PhysicalDataModel pdm, IDatabaseAdapter adapter, ITaskCollector collector, VersionHistoryService vhs)
Start the schema object creation tasks and wait for everything to completeprotected void
backfillResourceChangeLog()
Backfill the RESOURCE_CHANGE_LOG table if it is emptyprotected void
backfillResourceChangeLogDb2(TenantInfo ti)
backfill the resource_change_log table if it is emptyprotected void
buildAdminSchemaModel(PhysicalDataModel pdm)
Add the admin schema objects to thePhysicalDataModel
protected void
buildCommonModel(PhysicalDataModel pdm, boolean addFhirDataSchema, boolean addOAuthSchema, boolean addJavaBatchSchema)
Build a common PhysicalDataModel containing all the requested schemasprotected void
buildFhirDataSchemaModel(PhysicalDataModel pdm)
Add FHIR data schema objects to the givenPhysicalDataModel
protected void
buildJavaBatchSchemaModel(PhysicalDataModel pdm)
Add the JavaBatch schema objects to the givenPhysicalDataModel
protected void
buildOAuthSchemaModel(PhysicalDataModel pdm)
Add the OAuth schema objects to the givenPhysicalDataModel
protected boolean
checkCompatibility()
specific feature to check if it is compatible.protected boolean
checkIfTenantNameAndTenantKeyExists(Db2Adapter adapter, String tenantName, String tenantKey, boolean skip)
checks if tenant name and tenant key exists.protected void
checkSchemaForTenant()
Run a check to make sure that if the tenant already exists its schema matches the specified schema.protected void
configureConnectionPool()
Create a simple connection pool associated with our data source so that we can perform the DDL deployment in parallelprotected Connection
createConnection()
protected void
createSchemas()
Create the schemasprotected void
deleteTenantMeta()
Delete all the metadata associated with the named tenant.protected void
detachTenantPartitions(PhysicalDataModel pdm, TenantInfo tenantInfo)
Temporarily suspend RI so that tables which are the subject of foreign key relationships can have their partitions dropped.protected void
dropDetachedPartitionTables()
Drop any tables which have previously been detached.protected void
dropDetachedPartitionTables(PhysicalDataModel pdm, TenantInfo tenantInfo)
Drop any tables which have previously been detached.protected void
dropSchema()
Drop all the objects in the admin and data schemas.protected void
dropTenant()
Deallocate this tenant, dropping all the related partitions.protected TenantInfo
freezeTenant()
Mark the tenant so that it can no longer be accessed (this prevents the SET_TENANT method from authenticating the tenantName/tenantKey pair, so the SV_TENANT_ID variable never gets set).protected int
getExitStatus()
Get the program exit status from the environmentprotected TenantInfo
getTenantInfo()
protected List<TenantInfo>
getTenantList()
Get the list of tenants and the schemas each is currently defined in.protected void
grantPrivileges()
Grant the minimum required set of privileges on the FHIR schema objects to the grantTo user.protected void
grantPrivilegesForBatch()
Apply grants to the JavaBatch schema objectsprotected void
grantPrivilegesForFhirData()
Apply grants to the FHIR data schema objectsprotected void
grantPrivilegesForOAuth()
Apply grants to the OAuth schema objectsprotected boolean
isMultitenant()
Do we want to build the multitenant variant of the schema (currently only supported by DB2)protected void
listTenants()
List the tenants currently configuredvoid
loadPropertyFile(String filename)
Read the properties from the given fileprotected void
logStatusMessage(int status)
Write a final status message - useful for QA to review when checking the outputstatic void
main(String[] args)
Main entry pointprotected void
parseArgs(String[] args)
Parse the command-line arguments, building up the environment and establishing the run-listprotected void
populateResourceTypeAndParameterNameTableEntries(Integer tenantId)
populates for the given tenantId the RESOURCE_TYPE table.protected void
process()
Process the requested operationprotected void
refreshTenants()
Make sure all the tables has a partition created for the configured tenantprotected void
revokeTenantKey()
revokes a tenant key or if no tenant key is specified remove all of them for the given tenant.protected void
testTenant()
Check that we can call the set_tenant procedure successfully (which means that the tenant record exists in the tenants table)protected void
updateFhirSchema()
Update the FHIR data schemaprotected void
updateJavaBatchSchema()
Build and apply the JavaBatch schema changesprotected void
updateOauthSchema()
Build and apply the OAuth schema changesprotected void
updateProcedures()
Update the stored procedures used by FHIR to insert records into the FHIR resource tablesprotected boolean
updateSchema(PhysicalDataModel pdm)
Update the schema associated with the givenPhysicalDataModel
protected void
updateSchemas()
Process the schemas configured to be updatedvoid
updateVacuumSettings()
updates the vacuum settings for postgres.
-
-
-
Field Detail
-
ADMIN_SCHEMANAME
public static final String ADMIN_SCHEMANAME
- See Also:
- Constant Field Values
-
OAUTH_SCHEMANAME
public static final String OAUTH_SCHEMANAME
- See Also:
- Constant Field Values
-
BATCH_SCHEMANAME
public static final String BATCH_SCHEMANAME
- See Also:
- Constant Field Values
-
DATA_SCHEMANAME
public static final String DATA_SCHEMANAME
- See Also:
- Constant Field Values
-
-
Method Detail
-
createConnection
protected Connection createConnection()
- Returns:
- a created connection to the selected database
-
configureConnectionPool
protected void configureConnectionPool()
Create a simple connection pool associated with our data source so that we can perform the DDL deployment in parallel
-
buildAdminSchemaModel
protected void buildAdminSchemaModel(PhysicalDataModel pdm)
Add the admin schema objects to thePhysicalDataModel
- Parameters:
pdm
- the data model to build
-
buildOAuthSchemaModel
protected void buildOAuthSchemaModel(PhysicalDataModel pdm)
Add the OAuth schema objects to the givenPhysicalDataModel
- Parameters:
pdm
- the model to build
-
buildJavaBatchSchemaModel
protected void buildJavaBatchSchemaModel(PhysicalDataModel pdm)
Add the JavaBatch schema objects to the givenPhysicalDataModel
- Parameters:
pdm
-
-
applyModel
protected void applyModel(PhysicalDataModel pdm, IDatabaseAdapter adapter, ITaskCollector collector, VersionHistoryService vhs)
Start the schema object creation tasks and wait for everything to complete- Parameters:
pdm
-adapter
-collector
-vhs
-
-
checkCompatibility
protected boolean checkCompatibility()
specific feature to check if it is compatible.- Returns:
-
createSchemas
protected void createSchemas()
Create the schemas
-
updateSchemas
protected void updateSchemas()
Process the schemas configured to be updated
-
buildFhirDataSchemaModel
protected void buildFhirDataSchemaModel(PhysicalDataModel pdm)
Add FHIR data schema objects to the givenPhysicalDataModel
- Parameters:
pdm
- the data model being built
-
updateFhirSchema
protected void updateFhirSchema()
Update the FHIR data schema
-
updateOauthSchema
protected void updateOauthSchema()
Build and apply the OAuth schema changes
-
updateJavaBatchSchema
protected void updateJavaBatchSchema()
Build and apply the JavaBatch schema changes
-
updateSchema
protected boolean updateSchema(PhysicalDataModel pdm)
Update the schema associated with the givenPhysicalDataModel
- Returns:
- true if the database is new
-
populateResourceTypeAndParameterNameTableEntries
protected void populateResourceTypeAndParameterNameTableEntries(Integer tenantId)
populates for the given tenantId the RESOURCE_TYPE table.- Parameters:
tenantId
- the mt_id that is used to setup the partition. passing in null signals not multi-tenant.
-
dropSchema
protected void dropSchema()
Drop all the objects in the admin and data schemas. Typically used during development.
-
updateProcedures
protected void updateProcedures()
Update the stored procedures used by FHIR to insert records into the FHIR resource tables
-
buildCommonModel
protected void buildCommonModel(PhysicalDataModel pdm, boolean addFhirDataSchema, boolean addOAuthSchema, boolean addJavaBatchSchema)
Build a common PhysicalDataModel containing all the requested schemas- Parameters:
pdm
- the model to constructaddFhirDataSchema
- include objects for the FHIR data schemaaddOAuthSchema
- include objects for the Liberty OAuth schemaaddJavaBatchSchema
- include objects for the Liberty JavaBatch schema
-
grantPrivilegesForFhirData
protected void grantPrivilegesForFhirData()
Apply grants to the FHIR data schema objects
-
grantPrivilegesForOAuth
protected void grantPrivilegesForOAuth()
Apply grants to the OAuth schema objects
-
grantPrivilegesForBatch
protected void grantPrivilegesForBatch()
Apply grants to the JavaBatch schema objects
-
grantPrivileges
protected void grantPrivileges()
Grant the minimum required set of privileges on the FHIR schema objects to the grantTo user. All tenant data access is via this user, and is the only user the FHIR server itself is configured with.
-
isMultitenant
protected boolean isMultitenant()
Do we want to build the multitenant variant of the schema (currently only supported by DB2)- Returns:
-
addTenantKey
protected void addTenantKey()
Add a new tenant key so that we can rotate the values (add a new key, update config files, then remove the old key). This avoids any service interruption.
-
checkIfTenantNameAndTenantKeyExists
protected boolean checkIfTenantNameAndTenantKeyExists(Db2Adapter adapter, String tenantName, String tenantKey, boolean skip)
checks if tenant name and tenant key exists.- Parameters:
adapter
- the db2 adapter as this is a db2 feature only nowtenantName
- the tenant's nametenantKey
- tenant keyskip
- whether or not to skip over cases where this tenantName/tenantKey combination already exists- Returns:
- indicates if the tenantName/tenantKey exists
- Throws:
IllegalArgumentException
- if the tenantName/tenantKey combination already exists and theskip
argument is false
-
allocateTenant
protected void allocateTenant()
Allocate this tenant, creating new partitions if required.
-
checkSchemaForTenant
protected void checkSchemaForTenant()
Run a check to make sure that if the tenant already exists its schema matches the specified schema. This prevents users from accidentally creating a second instance of a tenant in a different schema
-
getTenantList
protected List<TenantInfo> getTenantList()
Get the list of tenants and the schemas each is currently defined in. Because this tenant-schema mapping isn't stored directly, it has to be inferred by looking up the schema from one of the tables we know should exist. The schema name may therefore be null if the tenant record (in FHIR_ADMIN.TENANTS) exists, but all the tables from that schema have been dropped.- Returns:
-
refreshTenants
protected void refreshTenants()
Make sure all the tables has a partition created for the configured tenant
-
listTenants
protected void listTenants()
List the tenants currently configured
-
testTenant
protected void testTenant()
Check that we can call the set_tenant procedure successfully (which means that the tenant record exists in the tenants table)
-
getTenantInfo
protected TenantInfo getTenantInfo()
-
freezeTenant
protected TenantInfo freezeTenant()
Mark the tenant so that it can no longer be accessed (this prevents the SET_TENANT method from authenticating the tenantName/tenantKey pair, so the SV_TENANT_ID variable never gets set).- Returns:
- the TenantInfo associated with the tenant
-
dropTenant
protected void dropTenant()
Deallocate this tenant, dropping all the related partitions. This needs to be idempotent because there are steps which must be run in separate transactions (due to how Db2 handles detaching partitions). This is further complicated by referential integrity constraints in the schema. See: - https://www.ibm.com/support/knowledgecenter/SSEPGG_11.5.0/com.ibm.db2.luw.admin.partition.doc/doc/t0021576.html The workaround described in the above link is: // Change the RI constraint to informational: 1. ALTER TABLE child ALTER FOREIGN KEY fk NOT ENFORCED; 2. ALTER TABLE parent DETACH PARTITION p0 INTO TABLE pdet; 3. SET INTEGRITY FOR child OFF; // Change the RI constraint back to enforced: 4. ALTER TABLE child ALTER FOREIGN KEY fk ENFORCED; 5. SET INTEGRITY FOR child ALL IMMEDIATE UNCHECKED; 6. Assuming that the CHILD table does not have any dependencies on partition P0, 7. and that no updates on the CHILD table are permitted until this UOW is complete, no RI violation is possible during this UOW. COMMIT WORK; Unfortunately, #7 above essentially requires that all writes cease until the UOW is completed and the integrity is enabled again on all the child (leaf) tables. Of course, this could be relaxed if the application is trusted not to mess up the referential integrity...which we know to be true for the FHIR server persistence layer. If the risk is deemed too high, tenant removal should be performed in a maintenance window.
-
dropDetachedPartitionTables
protected void dropDetachedPartitionTables()
Drop any tables which have previously been detached. The detach process is asynchronous, so this is a sort of garbage collection, sweeping up cruft left in the database.
-
dropDetachedPartitionTables
protected void dropDetachedPartitionTables(PhysicalDataModel pdm, TenantInfo tenantInfo)
Drop any tables which have previously been detached. Once all tables have been dropped, we go on to drop the tablespace. If the tablespace drop is successful, we know the cleanup is complete so we can update the tenant status accordingly- Parameters:
pdm
-tenantInfo
-
-
detachTenantPartitions
protected void detachTenantPartitions(PhysicalDataModel pdm, TenantInfo tenantInfo)
Temporarily suspend RI so that tables which are the subject of foreign key relationships can have their partitions dropped. A bit frustrating to have to go through this, because the child table partition will be detached before the parent anyway, so theoretically this workaround shouldn't be necessary. ALTER TABLE child ALTER FOREIGN KEY fk NOT ENFORCED; ALTER TABLE parent DETACH PARTITION p0 INTO TABLE pdet; SET INTEGRITY FOR child OFF; ALTER TABLE child ALTER FOREIGN KEY fk ENFORCED; SET INTEGRITY FOR child ALL IMMEDIATE UNCHECKED;
-
deleteTenantMeta
protected void deleteTenantMeta()
Delete all the metadata associated with the named tenant.
-
revokeTenantKey
protected void revokeTenantKey()
revokes a tenant key or if no tenant key is specified remove all of them for the given tenant.
-
parseArgs
protected void parseArgs(String[] args)
Parse the command-line arguments, building up the environment and establishing the run-list- Parameters:
args
-
-
loadPropertyFile
public void loadPropertyFile(String filename)
Read the properties from the given file- Parameters:
filename
-
-
addProperty
public void addProperty(String pair)
Parse the given key=value string and add to the properties being collected- Parameters:
pair
-
-
applyDataMigrationForV0010
protected void applyDataMigrationForV0010()
Perform the special data migration steps required for the V0010 version of the schema
-
applyDataMigrationForV0014
protected void applyDataMigrationForV0014()
-
backfillResourceChangeLog
protected void backfillResourceChangeLog()
Backfill the RESOURCE_CHANGE_LOG table if it is empty
-
backfillResourceChangeLogDb2
protected void backfillResourceChangeLogDb2(TenantInfo ti)
backfill the resource_change_log table if it is empty
-
updateVacuumSettings
public void updateVacuumSettings()
updates the vacuum settings for postgres.
-
process
protected void process()
Process the requested operation
-
getExitStatus
protected int getExitStatus()
Get the program exit status from the environment- Returns:
-
logStatusMessage
protected void logStatusMessage(int status)
Write a final status message - useful for QA to review when checking the output
-
main
public static void main(String[] args)
Main entry point- Parameters:
args
-
-
-