Skip to content

Commit

Permalink
Merge pull request #227 from DBCG/develop
Browse files Browse the repository at this point in the history
0.3.0 Release
  • Loading branch information
brynrhodes authored Jul 8, 2020
2 parents ed186b8 + ea5ebca commit a3166f0
Show file tree
Hide file tree
Showing 128 changed files with 4,115 additions and 3,138 deletions.
3 changes: 1 addition & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
.project
examples
target
derby.log
!target/jpaserver_derby_files
derby.log
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ org.eclipse.m2e.core.prefs
LogMessages.html

*.zip
*.7z

core.*
heapdump.*
Snap.*

.flattened-pom.xml

.flattened-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import java.lang.reflect.InvocationTargetException;
import java.sql.Driver;

import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;

Expand All @@ -35,7 +34,8 @@ public FhirServerConfig() {
ourLog.info("Server configured to " + (this.allowExternalReferences ? "allow" : "deny") + " external references");
ourLog.info("Server configured to " + (this.expungeEnabled ? "enable" : "disable") + " expunges");
ourLog.info("Server configured to " + (this.allowPlaceholderReferences ? "allow" : "deny") + " placeholder references");
ourLog.info("Server configured to " + (this.allowOverrideDefaultSearchParams ? "allow" : "deny") + " overriding default search params");
ourLog.info("Server configured to " + (this.allowOverrideDefaultSearchParams ? "allow" : "deny")
+ " overriding default search params");
}

/**
Expand All @@ -54,10 +54,11 @@ public DaoConfig daoConfig() {

Integer maxFetchSize = HapiProperties.getMaximumFetchSize();
retVal.setFetchSizeDefaultMaximum(maxFetchSize);
ourLog.info("Server configured to have a maximum fetch size of " + (maxFetchSize == Integer.MAX_VALUE? "'unlimited'": maxFetchSize));
ourLog.info("Server configured to have a maximum fetch size of "
+ (maxFetchSize == Integer.MAX_VALUE ? "'unlimited'" : maxFetchSize));

Long reuseCachedSearchResultsMillis = HapiProperties.getReuseCachedSearchResultsMillis();
retVal.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis );
retVal.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis);
ourLog.info("Server configured to cache search results for {} milliseconds", reuseCachedSearchResultsMillis);

return retVal;
Expand All @@ -75,16 +76,17 @@ public ModelConfig modelConfig() {
}

/**
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
* directory called "jpaserver_derby_files".
* The following bean configures the database connection. The 'url' property
* value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates
* that the server should save resources in a directory called
* "jpaserver_derby_files".
*
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
* A URL to a remote database could also be placed here, along with login
* credentials and other properties supported by BasicDataSource.
*/
@Bean(destroyMethod = "close")
public BasicDataSource dataSource()
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException
{
public BasicDataSource dataSource() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
BasicDataSource retVal = new BasicDataSource();
Driver driver = (Driver) Class.forName(HapiProperties.getDataSourceDriver()).getConstructor().newInstance();
retVal.setDriver(driver);
Expand All @@ -95,9 +97,9 @@ public BasicDataSource dataSource()
return retVal;
}


/**
* Do some fancy logging to create a nice access log that has details about each incoming request.
* Do some fancy logging to create a nice access log that has details about each
* incoming request.
*/
public LoggingInterceptor loggingInterceptor() {
LoggingInterceptor retVal = new LoggingInterceptor();
Expand All @@ -109,7 +111,8 @@ public LoggingInterceptor loggingInterceptor() {
}

/**
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
* This interceptor adds some pretty syntax highlighting in responses when a
* browser is detected
*/
@Bean(autowire = Autowire.BY_TYPE)
public ResponseHighlighterInterceptor responseHighlighterInterceptor() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package org.opencds.cqf.common.config;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

import com.google.common.annotations.VisibleForTesting;

import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
import com.google.common.annotations.VisibleForTesting;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

public class HapiProperties {
static final String ALLOW_EXTERNAL_REFERENCES = "allow_external_references";
Expand Down Expand Up @@ -47,6 +48,21 @@ public class HapiProperties {
static final String ALLOW_CONTAINS_SEARCHES = "allow_contains_searches";
static final String ALLOW_OVERRIDE_DEFAULT_SEARCH_PARAMS = "allow_override_default_search_params";
static final String EMAIL_FROM = "email.from";
static final String OAUTH_ENABLED = "oauth.enabled";
static final String OAUTH_SECURITY_CORS = "oauth.securityCors";
static final String OAUTH_SECURITY_URL = "oauth.securityUrl";
static final String OAUTH_SECURITY_EXT_AUTH_URL = "oauth.securityExtAuthUrl";
static final String OAUTH_SECURITY_EXT_AUTH_VALUE_URI = "oauth.securityExtAuthValueUri";
static final String OAUTH_SECURITY_EXT_TOKEN_URL = "oauth.securityExtTokenUrl";
static final String OAUTH_SECURITY_EXT_TOKEN_VALUE_URI = "oauth.securityExtTokenValueUri";
static final String OAUTH_SERVICE_SYSTEM = "oauth.serviceSystem";
static final String OAUTH_SERVICE_CODE = "oauth.serviceCode";
static final String OAUTH_SERVICE_DISPLAY = "oauth.serviceDisplay";
static final String OAUTH_SERVICE_TEXT = "oauth.serviceText";
static final String QUESTIONNAIRE_RESPONSE_ENABLED = "questionnaireResponseExtract.enabled";
static final String QUESTIONNAIRE_RESPONSE_ENDPOINT = "questionnaireResponseExtract.endpoint";
static final String QUESTIONNAIRE_RESPONSE_USERNAME = "questionnaireResponseExtract.username";
static final String QUESTIONNAIRE_RESPONSE_PASSWORD = "questionnaireResponseExtract.password";

private static Properties properties;

Expand All @@ -59,8 +75,8 @@ public static void forceReload() {
}

/**
* This is mostly here for unit tests. Use the actual properties file
* to set values
* This is mostly here for unit tests. Use the actual properties file to set
* values
*/
@VisibleForTesting
public static void setProperty(String theKey, String theValue) {
Expand All @@ -70,39 +86,41 @@ public static void setProperty(String theKey, String theValue) {
public static Properties getProperties() {
if (properties == null) {
// Load the configurable properties file
try (InputStream in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES)){
try (InputStream in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES)) {
HapiProperties.properties = new Properties();
HapiProperties.properties.load(in);
} catch (Exception e) {
throw new ConfigurationException("Could not load HAPI properties", e);
}

Properties overrideProps = loadOverrideProperties();
if(overrideProps != null) {
properties.putAll(overrideProps);
if (overrideProps != null) {
properties.putAll(overrideProps);
}
}

return properties;
}

/**
* If a configuration file path is explicitly specified via -Dhapi.properties=<path>, the properties there will
* be used to override the entries in the default hapi.properties file (currently under WEB-INF/classes)
* @return properties loaded from the explicitly specified configuraiton file if there is one, or null otherwise.
* If a configuration file path is explicitly specified via
* -Dhapi.properties=<path>, the properties there will be used to override the
* entries in the default hapi.properties file (currently under WEB-INF/classes)
*
* @return properties loaded from the explicitly specified configuraiton file if
* there is one, or null otherwise.
*/
private static Properties loadOverrideProperties() {
String confFile = System.getProperty(HAPI_PROPERTIES + "." + HapiProperties.getProperty(FHIR_VERSION));
if (confFile == null) {
confFile = System.getProperty(HAPI_PROPERTIES);
}
if(confFile != null) {
if (confFile != null) {
try {
Properties props = new Properties();
props.load(new FileInputStream(confFile));
return props;
}
catch (Exception e) {
} catch (Exception e) {
throw new ConfigurationException("Could not load HAPI properties file: " + confFile, e);
}
}
Expand Down Expand Up @@ -213,7 +231,8 @@ public static String getLoggerName() {
}

public static String getLoggerFormat() {
return HapiProperties.getProperty(LOGGER_FORMAT, "Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
return HapiProperties.getProperty(LOGGER_FORMAT,
"Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
}

public static String getLoggerErrorFormat() {
Expand All @@ -228,16 +247,17 @@ public static String getDataSourceDriver() {
return HapiProperties.getProperty(DATASOURCE_DRIVER, "org.apache.derby.jdbc.EmbeddedDriver");
}

public static Object getDriver() {
return new org.apache.derby.jdbc.EmbeddedDriver();
}
// public static Object getDriver() {
// return new org.apache.derby.jdbc.EmbeddedDriver();
// }

public static Integer getDataSourceMaxPoolSize() {
return HapiProperties.getIntegerProperty(DATASOURCE_MAX_POOL_SIZE, 10);
}

public static String getDataSourceUrl() {
return HapiProperties.getProperty(DATASOURCE_URL, "jdbc:derby:directory:target/jpaserver_derby_files;create=true");
return HapiProperties.getProperty(DATASOURCE_URL,
"jdbc:derby:directory:target/jpaserver_derby_files;create=true");
}

public static String getDataSourceUsername() {
Expand Down Expand Up @@ -340,4 +360,22 @@ public static Long getReuseCachedSearchResultsMillis() {
String value = HapiProperties.getProperty(REUSE_CACHED_SEARCH_RESULTS_MILLIS, "-1");
return Long.valueOf(value);
}

//************************* OAuth *******************************************************
public static Boolean getOAuthEnabled(){return HapiProperties.getBooleanProperty(OAUTH_ENABLED, false);}
public static Boolean getOauthSecurityCors(){return HapiProperties.getBooleanProperty(OAUTH_SECURITY_CORS, true);}
public static String getOauthSecurityUrl(){return HapiProperties.getProperty(OAUTH_SECURITY_URL, "");}
public static String getOauthSecurityExtAuthUrl(){return HapiProperties.getProperty(OAUTH_SECURITY_EXT_AUTH_URL, "");}
public static String getOauthSecurityExtAuthValueUri(){return HapiProperties.getProperty(OAUTH_SECURITY_EXT_AUTH_VALUE_URI, "");}
public static String getOauthSecurityExtTokenUrl(){return HapiProperties.getProperty(OAUTH_SECURITY_EXT_TOKEN_URL, "");}
public static String getOauthSecurityExtTokenValueUri(){return HapiProperties.getProperty(OAUTH_SECURITY_EXT_TOKEN_VALUE_URI, "");}
public static String getOauthServiceSystem(){return HapiProperties.getProperty(OAUTH_SERVICE_SYSTEM, "");}
public static String getOauthServiceCode(){return HapiProperties.getProperty(OAUTH_SERVICE_CODE, "");}
public static String getOauthServiceDisplay(){return HapiProperties.getProperty(OAUTH_SERVICE_DISPLAY, "");}
public static String getOauthServiceText(){return HapiProperties.getProperty(OAUTH_SERVICE_TEXT, "");}

public static Boolean getQuestionnaireResponseExtractEnabled(){return HapiProperties.getBooleanProperty(QUESTIONNAIRE_RESPONSE_ENABLED, false);}
public static String getQuestionnaireResponseExtractEndpoint() {return HapiProperties.getProperty(QUESTIONNAIRE_RESPONSE_ENDPOINT);}
public static String getQuestionnaireResponseExtractUserName(){return HapiProperties.getProperty(QUESTIONNAIRE_RESPONSE_USERNAME);};
public static String getQuestionnaireResponseExtractPassword(){return HapiProperties.getProperty(QUESTIONNAIRE_RESPONSE_PASSWORD);};
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.opencds.cqf.common.evaluation;

import org.opencds.cqf.cql.data.DataProvider;
import org.opencds.cqf.cql.terminology.TerminologyProvider;
import org.opencds.cqf.cql.engine.data.DataProvider;
import org.opencds.cqf.cql.engine.terminology.TerminologyProvider;

// TODO: This interface is a partial duplicate of the provider factory interface
// in the cql service layer. We need another round of refactoring to consolidate that.
Expand All @@ -12,5 +12,6 @@ public interface EvaluationProviderFactory {

public DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider);

public TerminologyProvider createTerminologyProvider(String model, String version, String url, String user, String pass);
public TerminologyProvider createTerminologyProvider(String model, String version, String url, String user,
String pass);
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
package org.opencds.cqf.common.evaluation;

import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.CqlTranslatorException;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.cql2elm.CqlTranslatorException.ErrorSeverity;
import org.cqframework.cql.cql2elm.LibraryBuilder.SignatureLevel;
import org.cqframework.cql.elm.execution.Library;
import org.cqframework.cql.elm.execution.VersionedIdentifier;
import static org.opencds.cqf.common.helpers.TranslatorHelper.errorsToString;
import static org.opencds.cqf.common.helpers.TranslatorHelper.getTranslator;
import static org.opencds.cqf.common.helpers.TranslatorHelper.readLibrary;

import javax.xml.bind.JAXBException;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static org.opencds.cqf.common.helpers.TranslatorHelper.*;
import javax.xml.bind.JAXBException;

import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.CqlTranslatorException;
import org.cqframework.cql.cql2elm.CqlTranslatorOptions;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.cqframework.cql.elm.execution.VersionedIdentifier;

public class LibraryLoader implements org.opencds.cqf.cql.execution.LibraryLoader {
public class LibraryLoader implements org.opencds.cqf.cql.engine.execution.LibraryLoader {

private LibraryManager libraryManager;
private ModelManager modelManager;
Expand Down Expand Up @@ -78,12 +80,8 @@ private Library loadLibrary(VersionedIdentifier libraryIdentifier) {
.withVersion(libraryIdentifier.getVersion());

ArrayList<CqlTranslatorException> errors = new ArrayList<>();
org.hl7.elm.r1.Library translatedLibrary = libraryManager.resolveLibrary(identifier, ErrorSeverity.Error,
SignatureLevel.All,
new CqlTranslator.Options[] { CqlTranslator.Options.EnableAnnotations,
CqlTranslator.Options.EnableLocators, CqlTranslator.Options.DisableListDemotion,
CqlTranslator.Options.DisableListPromotion, CqlTranslator.Options.DisableMethodInvocation },
errors).getLibrary();
org.hl7.elm.r1.Library translatedLibrary = libraryManager
.resolveLibrary(identifier, CqlTranslatorOptions.defaultOptions(), errors).getLibrary();

if (CqlTranslatorException.HasErrors(errors)) {
throw new IllegalArgumentException(errorsToString(errors));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.opencds.cqf.common.helpers;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;

public class ClientHelper {

/*
* TODO - depending on future needs: 1. add OAuth 2. change if to switch to
* accommodate additional FHIR versions
*/
private static IGenericClient getRestClient(FhirContext fhirContext, String url) {
fhirContext.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
return fhirContext.newRestfulGenericClient(url);
}

// Overload in case you need to specify a specific version of the context
public static IGenericClient getClient(FhirContext fhirContext, String url, String user, String password) {
IGenericClient client = getRestClient(fhirContext, url);
registerAuth(client, user, password);

return client;
}

private static void registerAuth(IGenericClient client, String userId, String password) {
if (userId != null) {
BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(userId, password);
client.registerInterceptor(authInterceptor);
}
}
}
Loading

0 comments on commit a3166f0

Please sign in to comment.