com.ibm.fhir.persistence.blob.app.Main Maven / Gradle / Ivy
/*
* (C) Copyright IBM Corp. 2022
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.ibm.fhir.persistence.blob.app;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.ibm.fhir.config.FHIRConfiguration;
import com.ibm.fhir.database.utils.api.ITransaction;
import com.ibm.fhir.database.utils.model.DbType;
import com.ibm.fhir.database.utils.pool.DatabaseSupport;
import com.ibm.fhir.exception.FHIRException;
import com.ibm.fhir.persistence.blob.BlobContainerManager;
import com.ibm.fhir.persistence.blob.BlobName;
import com.ibm.fhir.persistence.jdbc.cache.ResourceTypeMaps;
import com.ibm.fhir.persistence.jdbc.dao.impl.ReadResourceTypesDAO;
import com.ibm.fhir.schema.model.ResourceType;
/**
* Standalone application to provide support services (like reconciliation) for
* payload offload using Azure Blob
*/
public class Main {
private static final Logger logger = Logger.getLogger(Main.class.getName());
// properties for connecting to the database
private final Properties databaseProperties = new Properties();
private String fhirConfigDir;
private String tenantId;
private String dsId;
private DbType dbType;
private boolean reconcile;
private boolean createContainer;
private boolean dryRun = true;
private String continuationToken = null;
// A list of resources for which we want to read the blob contents
private final List resourceList = new ArrayList<>();
// Provides access to database connections and transaction handling
private DatabaseSupport dbSupport;
// Support for resource type lookup when we have a database config
private ResourceTypeMaps resourceTypeMaps;
// Stop scanning after this number of seconds. Use continuationToken to continue
private int maxScanSeconds = 120;
/**
* Parse the command line arguments
* @param args
*/
protected void parseArgs(String[] args) {
for (int i=0; i 0 && this.dbType != null) {
this.dbSupport = new DatabaseSupport(this.databaseProperties, dbType);
this.dbSupport.init();
fillResourceTypeMaps();
}
// Run reconciliation OR read resources, not both
if (this.reconcile) {
runReconciliation();
didSomething = true;
} else if (this.resourceList.size() > 0) {
doReads();
didSomething = true;
}
if (!didSomething) {
throw new IllegalArgumentException("Must specify at least one action");
}
}
/**
* Read the resource types from the database and populate the two lookup
* maps for easy conversion between resource type id and resource type name
*/
private void fillResourceTypeMaps() {
logger.info("Filling resource type maps");
try (ITransaction tx = dbSupport.getTransaction()) {
try (Connection c = dbSupport.getConnection()) {
ReadResourceTypesDAO dao = new ReadResourceTypesDAO();
List resourceTypes = dao.run(dbSupport.getTranslator(), c);
this.resourceTypeMaps = new ResourceTypeMaps();
this.resourceTypeMaps.init(resourceTypes);
} catch (SQLException x) {
tx.setRollbackOnly();
throw dbSupport.getTranslator().translate(x);
}
}
}
/**
* Create the container
*/
private void createContainer() throws FHIRException {
CreateContainer action = new CreateContainer(this.tenantId, this.dsId, this.dryRun);
action.run();
}
/**
* Run the reconciliation process
*/
protected void runReconciliation() throws Exception {
if (this.databaseProperties == null) {
// bad args on the CLI
throw new IllegalArgumentException("Missing database configuration which is required to run reconciliation");
}
if (this.resourceTypeMaps == null || !this.resourceTypeMaps.isInitialized()) {
throw new IllegalStateException("ResourceTypeMaps not initialized");
}
PayloadReconciliation process = new PayloadReconciliation(this.tenantId, this.dsId, dbSupport, this.resourceTypeMaps, dryRun, this.maxScanSeconds);
String newContinuationToken = process.run(this.continuationToken);
if (newContinuationToken == null) {
logger.info("Scan complete");
}
}
/**
* Read each of the resources in the resourceList
* @throws Exception
*/
protected void doReads() throws Exception {
for (String nm: this.resourceList) {
// resourceTypeMaps may be null or empty if no database config
// has been provided, in which case BlobName can't do any
// conversion
BlobName blobName = BlobName.create(resourceTypeMaps, nm);
if (blobName.getResourceTypeId() < 0) {
throw new IllegalArgumentException("Must use resourceTypeId for path, or provide a database configuration to allow lookup");
}
ReadBlobValue action = new ReadBlobValue(this.tenantId, this.dsId, this.resourceTypeMaps, blobName);
action.run();
}
}
/**
* Shut down any thread pools so we can make a quick exit
*/
protected void terminate() {
BlobContainerManager.shutdown();
}
/**
* Entry point
* @param args
*/
public static void main(String[] args) {
Main m = new Main();
try {
m.parseArgs(args);
m.process();
m.terminate();
} catch (Exception x) {
logger.log(Level.SEVERE, "failed", x);
System.exit(-1);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy