Improve the error message thrown by JPA server

This commit is contained in:
James Agnew 2018-05-11 17:03:48 -04:00
parent 38e6edf4ae
commit f1ba0016b2
33 changed files with 527 additions and 366 deletions

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.cds.example;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
@ -59,18 +60,16 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -6,6 +6,9 @@ import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.BaseConfig;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
@ -84,14 +87,14 @@ public class FhirServerConfigCommon {
return dataSource;
}
public static LocalContainerEntityManagerFactoryBean getEntityManagerFactory(Environment env, DataSource dataSource) {
public static LocalContainerEntityManagerFactoryBean getEntityManagerFactory(Environment env, DataSource dataSource, FhirContext theCtx) {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
BaseConfig.configureEntityManagerFactory(retVal, theCtx);
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource);
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties(env));
return retVal;
}
@ -134,7 +137,7 @@ public class FhirServerConfigCommon {
extraProperties.put("hibernate.dialect", org.hibernate.dialect.PostgreSQL9Dialect.class.getName());
}
else if(dbUrl != null && dbUrl.indexOf("derby") > -1) {
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
}
boolean hibernateCreate = new Boolean(env.getProperty(Utils.HIBERNATE_CREATE));
logger.info("------DB hibernateCreate: " + hibernateCreate);

View File

@ -57,6 +57,8 @@ ca.uhn.fhir.validation.ValidationResult.noIssuesDetected=No issues detected duri
# JPA Messages
ca.uhn.fhir.jpa.config.HapiFhirHibernateJpaDialect.resourceVersionConstraintFailure=The operation has failed with a version constraint failure. This generally means that two clients/threads were trying to update the same resource at the same time, and this request was chosen as the failing request.
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.externalReferenceNotAllowed=Resource contains external reference to URL "{0}" but this server is not configured to allow external references
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.incomingNoopInTransaction=Transaction contains resource with operation NOOP. This is only valid as a response operation, not in a request
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlInvalidResourceType=Invalid match URL "{0}" - Unknown resource type: "{1}"

View File

@ -26,10 +26,7 @@ import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
import com.google.common.base.Charsets;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.*;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
@ -57,9 +54,6 @@ import java.util.zip.GZIPInputStream;
import static org.apache.commons.lang3.StringUtils.*;
public abstract class BaseCommand implements Comparable<BaseCommand> {
// TODO: Don't use qualified names for loggers in HAPI CLI.
private static final Logger ourLog = LoggerFactory.getLogger(BaseCommand.class);
protected static final String BASE_URL_PARAM = "t";
protected static final String BASE_URL_PARAM_LONGOPT = "target";
protected static final String BASE_URL_PARAM_NAME = "target";
@ -78,8 +72,8 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
protected static final String VERBOSE_LOGGING_PARAM = "l";
protected static final String VERBOSE_LOGGING_PARAM_LONGOPT = "logging";
protected static final String VERBOSE_LOGGING_PARAM_DESC = "If specified, verbose logging will be used.";
// TODO: Don't use qualified names for loggers in HAPI CLI.
private static final Logger ourLog = LoggerFactory.getLogger(BaseCommand.class);
protected FhirContext myFhirCtx;
public BaseCommand() {
@ -104,13 +98,8 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
addRequiredOption(theOptions, FHIR_VERSION_PARAM, FHIR_VERSION_PARAM_LONGOPT, FHIR_VERSION_PARAM_NAME, FHIR_VERSION_PARAM_DESC + versions);
}
protected void addVerboseLoggingOption(Options theOptions) {
addOptionalOption(theOptions, VERBOSE_LOGGING_PARAM, VERBOSE_LOGGING_PARAM_LONGOPT, false, VERBOSE_LOGGING_PARAM_DESC);
}
private void addOption(Options theOptions, boolean theRequired, String theOpt, String theLong, boolean theHasArgument, String theArgumentName, String theDescription) {
Option option = new Option(theOpt, theLong, theHasArgument, theDescription);
option.setRequired(theRequired);
private void addOption(Options theOptions, OptionGroup theOptionGroup, boolean theRequired, String theOpt, String theLongOpt, boolean theHasArgument, String theArgumentName, String theDescription) {
Option option = createOption(theRequired, theOpt, theLongOpt, theHasArgument, theDescription);
if (theHasArgument && isNotBlank(theArgumentName)) {
option.setArgName(theArgumentName);
}
@ -119,30 +108,48 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
if (theOptions.getOption(theOpt) != null) {
throw new IllegalStateException("Duplicate option: " + theOpt);
}
if (theOptionGroup != null && theOptionGroup.getOptions().stream().anyMatch(t-> theOpt.equals(t.getOpt()))) {
throw new IllegalStateException("Duplicate option: " + theOpt);
}
if (isNotBlank(theLong)) {
if (theOptions.getOption(theLong) != null) {
throw new IllegalStateException("Duplicate option: " + theLong);
}
if (isNotBlank(theLongOpt)) {
if (theOptions.getOption(theLongOpt) != null) {
throw new IllegalStateException("Duplicate option: " + theLongOpt);
}
if (theOptionGroup != null && theOptionGroup.getOptions().stream().anyMatch(t-> theLongOpt.equals(t.getLongOpt()))) {
throw new IllegalStateException("Duplicate option: " + theOpt);
}
}
if (theOptionGroup != null) {
theOptionGroup.addOption(option);
} else {
theOptions.addOption(option);
}
}
protected void addOptionalOption(Options theOptions, String theOpt, String theLong, boolean theTakesArgument, String theDescription) {
addOption(theOptions, false, theOpt, theLong, theTakesArgument, null, theDescription);
addOption(theOptions, null, false, theOpt, theLong, theTakesArgument, null, theDescription);
}
protected void addOptionalOption(Options theOptions, String theOpt, String theLong, String theArgumentName, String theDescription) {
addOption(theOptions, false, theOpt, theLong, isNotBlank(theArgumentName), theArgumentName, theDescription);
addOption(theOptions, null, false, theOpt, theLong, isNotBlank(theArgumentName), theArgumentName, theDescription);
}
protected void addOptionalOption(Options theOptions, OptionGroup theOptionGroup, String theOpt, String theLong, String theArgumentName, String theDescription) {
addOption(theOptions, theOptionGroup, false, theOpt, theLong, isNotBlank(theArgumentName), theArgumentName, theDescription);
}
protected void addRequiredOption(Options theOptions, String theOpt, String theLong, boolean theTakesArgument, String theDescription) {
addOption(theOptions, true, theOpt, theLong, theTakesArgument, null, theDescription);
addOption(theOptions, null, true, theOpt, theLong, theTakesArgument, null, theDescription);
}
protected void addRequiredOption(Options theOptions, String theOpt, String theLong, String theArgumentName, String theDescription) {
addOption(theOptions, true, theOpt, theLong, isNotBlank(theArgumentName), theArgumentName, theDescription);
addOption(theOptions, null, true, theOpt, theLong, isNotBlank(theArgumentName), theArgumentName, theDescription);
}
protected void addVerboseLoggingOption(Options theOptions) {
addOptionalOption(theOptions, VERBOSE_LOGGING_PARAM, VERBOSE_LOGGING_PARAM_LONGOPT, false, VERBOSE_LOGGING_PARAM_DESC);
}
@Override
@ -150,6 +157,12 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
return getCommandName().compareTo(theO.getCommandName());
}
private Option createOption(boolean theRequired, String theOpt, String theLong, boolean theHasArgument, String theDescription) {
Option option = new Option(theOpt, theLong, theHasArgument, theDescription);
option.setRequired(theRequired);
return option;
}
protected Reader createReader(File theInputFile) throws IOException {
InputStream inputStream = new FileInputStream(theInputFile);
if (theInputFile.getName().toLowerCase().endsWith(".gz")) {

View File

@ -68,18 +68,18 @@ public class ValidateCommand extends BaseCommand {
addFhirVersionOption(retVal);
OptionGroup source = new OptionGroup();
addOptionalOption(source, "n", "file", true, "filename", "The name of the file to validate");
addOptionalOption(source, "d", "data", true, "text", "The text to validate");
addOptionalOption(retVal, source, "n", "file", "filename", "The name of the file to validate");
addOptionalOption(retVal, source, "d", "data", "text", "The text to validate");
retVal.addOptionGroup(source);
retVal.addOption("p", "profile", false, "Validate using Profiles (StructureDefinition / ValueSet)");
retVal.addOption("r", "fetch-remote", false,
"Allow fetching remote resources (in other words, if a resource being validated refers to an external StructureDefinition, Questionnaire, etc. this flag allows the validator to access the internet to try and fetch this resource)");
addOptionalOption(retVal, "l", "fetch-local", true, "filename", "Fetch a profile locally and use it if referenced"));
addOptionalOption(retVal, "l", "fetch-local", "filename", "Fetch a profile locally and use it if referenced");
addOptionalOption(retVal, null, "igpack", true, "If specified, provides the filename of an IGPack file to include in validation");
addOptionalOption(retVal, "x", "xsd", false, "Validate using Schemas");
addOptionalOption(retVal, "s", "sch", false, "Validate using Schematrons");
addOptionalOption(retVal, "e", "encoding", true, "encoding", "File encoding (default is UTF-8)");
addOptionalOption(retVal, "e", "encoding","encoding", "File encoding (default is UTF-8)");
return retVal;
}

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.demo;
import java.util.Properties;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -15,7 +16,7 @@ public class FhirDbConfig {
@Bean()
public Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -65,7 +65,7 @@ public class FhirServerConfig extends BaseJavaConfigDstu2 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");

View File

@ -68,11 +68,9 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(myJpaProperties);
return retVal;
}

View File

@ -68,11 +68,9 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(myJpaProperties);
return retVal;
}

View File

@ -20,12 +20,15 @@ package ca.uhn.fhir.jpa.config;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.jpa.search.*;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
import ca.uhn.fhir.jpa.subscription.websocket.SubscriptionWebsocketInterceptor;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
@ -35,6 +38,9 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate5.HibernateExceptionTranslator;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
@ -47,7 +53,7 @@ import javax.annotation.Resource;
@Configuration
@EnableScheduling
@EnableJpaRepositories(basePackages = "ca.uhn.fhir.jpa.dao.data")
public class BaseConfig implements SchedulingConfigurer {
public abstract class BaseConfig implements SchedulingConfigurer {
public static final String TASK_EXECUTOR_NAME = "hapiJpaTaskExecutor";
@ -67,6 +73,29 @@ public class BaseConfig implements SchedulingConfigurer {
return retVal;
}
/**
* This method should be overridden to provide an actual completed
* bean, but it provides a partially completed entity manager
* factory with HAPI FHIR customizations
*/
protected LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
configureEntityManagerFactory(retVal, fhirContext());
return retVal;
}
public abstract FhirContext fhirContext();
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public HibernateJpaDialect hibernateJpaDialectIntance() {
return new HibernateJpaDialect();
}
@Bean()
public ScheduledExecutorFactoryBean scheduledExecutorService() {
ScheduledExecutorFactoryBean b = new ScheduledExecutorFactoryBean();
@ -120,6 +149,16 @@ public class BaseConfig implements SchedulingConfigurer {
return retVal;
}
public static void configureEntityManagerFactory(LocalContainerEntityManagerFactoryBean theFactory, FhirContext theCtx) {
theFactory.setJpaDialect(hibernateJpaDialect(theCtx.getLocalizer()));
theFactory.setPackagesToScan("ca.uhn.fhir.jpa.entity");
theFactory.setPersistenceProvider(new HibernatePersistenceProvider());
}
private static HibernateJpaDialect hibernateJpaDialect(HapiLocalizer theLocalizer) {
return new HapiFhirHibernateJpaDialect(theLocalizer);
}
/**
* This lets the "@Value" fields reference properties from the properties file
*/

View File

@ -53,6 +53,11 @@ public class BaseDstu2Config extends BaseConfig {
return fhirContextDstu2();
}
@Override
public FhirContext fhirContext() {
return fhirContextDstu2();
}
@Bean(name = "myFhirContextDstu2")
@Lazy
public FhirContext fhirContextDstu2() {

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.jpa.config;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import org.hibernate.HibernateException;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
public class HapiFhirHibernateJpaDialect extends HibernateJpaDialect {
private HapiLocalizer myLocalizer;
/**
* Constructor
*/
public HapiFhirHibernateJpaDialect(HapiLocalizer theLocalizer) {
myLocalizer = theLocalizer;
}
@Override
protected DataAccessException convertHibernateAccessException(HibernateException theException) {
if (theException instanceof ConstraintViolationException) {
if (ResourceHistoryTable.IDX_RESVER_ID_VER.equals(((ConstraintViolationException) theException).getConstraintName())) {
throw new PreconditionFailedException(myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "resourceVersionConstraintFailure"));
}
}
return super.convertHibernateAccessException(theException);
}
}

View File

@ -15,7 +15,6 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcDstu3;
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
import ca.uhn.fhir.validation.IValidatorModule;
import org.apache.commons.lang3.time.DateUtils;
@ -29,8 +28,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.Map;
/*
* #%L
* HAPI FHIR JPA Server
@ -55,6 +52,11 @@ import java.util.Map;
@EnableTransactionManagement
public class BaseDstu3Config extends BaseConfig {
@Override
public FhirContext fhirContext() {
return fhirContextDstu3();
}
@Bean
@Primary
public FhirContext fhirContextDstu3() {

View File

@ -16,7 +16,6 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
import ca.uhn.fhir.validation.IValidatorModule;
import org.apache.commons.lang3.time.DateUtils;
@ -32,8 +31,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.Map;
/*
* #%L
* HAPI FHIR JPA Server
@ -58,6 +55,11 @@ import java.util.Map;
@EnableTransactionManagement
public class BaseR4Config extends BaseConfig {
@Override
public FhirContext fhirContext() {
return fhirContextR4();
}
@Bean
@Primary
public FhirContext fhirContextR4() {

View File

@ -78,6 +78,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
@ -98,6 +99,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import static org.apache.commons.lang3.StringUtils.*;
@SuppressWarnings("WeakerAccess")
@Repository
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
public static final long INDEX_STATUS_INDEXED = 1L;

View File

@ -32,7 +32,7 @@ import java.util.Collection;
//@formatter:off
@Entity
@Table(name = "HFJ_RES_VER", uniqueConstraints = {
@UniqueConstraint(name = "IDX_RESVER_ID_VER", columnNames = {"RES_ID", "RES_VER"})
@UniqueConstraint(name = ResourceHistoryTable.IDX_RESVER_ID_VER, columnNames = {"RES_ID", "RES_VER"})
}, indexes = {
@Index(name = "IDX_RESVER_TYPE_DATE", columnList = "RES_TYPE,RES_UPDATED"),
@Index(name = "IDX_RESVER_ID_DATE", columnList = "RES_ID,RES_UPDATED"),
@ -42,6 +42,7 @@ import java.util.Collection;
public class ResourceHistoryTable extends BaseHasResource implements Serializable {
private static final long serialVersionUID = 1L;
public static final String IDX_RESVER_ID_VER = "IDX_RESVER_ID_VER";
@Id
@SequenceGenerator(name = "SEQ_RESOURCE_HISTORY_ID", sequenceName = "SEQ_RESOURCE_HISTORY_ID")

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.jpa.util;
import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
public class DerbyTenSevenHapiFhirDialect extends DerbyTenSevenDialect {
private static final Logger ourLog = LoggerFactory.getLogger(DerbyTenSevenHapiFhirDialect.class);
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException theSqlException) throws NumberFormatException {
switch (theSqlException.getSQLState()) {
case "23505":
return this.extractUsingTemplate("unique or primary key constraint or unique index identified by '", "'", theSqlException.getMessage());
default:
return null;
}
}
};
}
}

View File

@ -45,11 +45,9 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu2");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -59,7 +57,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
extraProperties.put("hibernate.search.default.directory_provider", "ram");
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");

View File

@ -135,10 +135,9 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu3");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
@ -150,7 +149,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
extraProperties.put("hibernate.search.default.directory_provider", "ram");
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");

View File

@ -27,11 +27,7 @@ public class TestDstu3WithoutLuceneConfig extends TestDstu3Config {
@Override
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu3");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -41,7 +37,7 @@ public class TestDstu3WithoutLuceneConfig extends TestDstu3Config {
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
extraProperties.put("hibernate.search.autoregister_listeners", "false");
return extraProperties;
}

View File

@ -12,8 +12,10 @@ import org.hibernate.query.criteria.LiteralHandlingMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.orm.hibernate5.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
@ -115,11 +117,9 @@ public class TestR4Config extends BaseJavaConfigR4 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaR4");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -130,7 +130,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
extraProperties.put("hibernate.search.model_mapping", ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory.class.getName());
extraProperties.put("hibernate.search.default.directory_provider", "ram");
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");

View File

@ -27,11 +27,8 @@ public class TestR4WithoutLuceneConfig extends TestR4Config {
@Override
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("PU_HapiFhirJpaR4");
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -41,7 +38,7 @@ public class TestR4WithoutLuceneConfig extends TestR4Config {
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
extraProperties.put("hibernate.search.autoregister_listeners", "false");
return extraProperties;
}

View File

@ -1,27 +1,41 @@
package ca.uhn.fhir.jpa.dao.r4;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.util.*;
import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.*;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4.model.OperationOutcome.IssueType;
import org.hl7.fhir.r4.model.Quantity.QuantityComparator;
import org.hl7.fhir.instance.model.api.*;
import org.junit.*;
import org.mockito.ArgumentCaptor;
import org.springframework.transaction.TransactionDefinition;
@ -29,22 +43,19 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
@SuppressWarnings({"unchecked", "deprecation"})
public class FhirResourceDaoR4Test extends BaseJpaR4Test {
@ -82,47 +93,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
}
@Test
public void testSaveAndReturnCollectionBundle() throws IOException {
String input = IOUtils.toString(FhirResourceDaoR4Test.class.getResourceAsStream("/r4/collection-bundle.json"));
Bundle inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
myBundleDao.update(inputBundle);
Bundle outputBundle = myBundleDao.read(new IdType("cftest"));
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outputBundle));
for (BundleEntryComponent next : outputBundle.getEntry()) {
assertTrue(next.getResource().getIdElement().hasIdPart());
}
}
/**
* See #773
*/
@Test
public void testDeleteResourceWithOutboundDeletedResources() {
myDaoConfig.setEnforceReferentialIntegrityOnDelete(false);
Organization org = new Organization();
org.setId("ORG");
org.setName("ORG");
myOrganizationDao.update(org);
Patient pat = new Patient();
pat.setId("PAT");
pat.setActive(true);
pat.setManagingOrganization(new Reference("Organization/ORG"));
myPatientDao.update(pat);
myOrganizationDao.delete(new IdType("Organization/ORG"));
myPatientDao.delete(new IdType("Patient/PAT"));
}
@Before
public void beforeDisableResultReuse() {
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
@ -161,7 +131,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
}
private void sortCodings(List<Coding> theSecLabels) {
Collections.sort(theSecLabels, new Comparator<Coding>() {
@Override
@ -453,6 +422,54 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
assertGone(id.toUnqualifiedVersionless());
}
@Test
public void testConflictingUpdates() throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(5);
try {
Patient p = new Patient();
p.setActive(true);
IIdType id = myPatientDao.create(p).getId();
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Patient updatePatient = new Patient();
updatePatient.setId(id.toUnqualifiedVersionless());
updatePatient.addIdentifier().setSystem("" + i);
updatePatient.setActive(true);
int finalI = i;
Future<String> future = pool.submit(() -> {
ourLog.info("Starting update {}", finalI);
try {
try {
myPatientDao.update(updatePatient);
} catch (PreconditionFailedException e) {
assertEquals("The operation has failed with a version constraint failure. This generally means that two clients/threads were trying to update the same resource at the same time, and this request was chosen as the failing request.", e.getMessage());
}
} catch (Exception e) {
ourLog.error("Failure", e);
return e.toString();
}
ourLog.info("Finished update {}", finalI);
return null;
});
futures.add(future);
}
for (Future<String> next : futures) {
String nextError = next.get();
if (StringUtils.isNotBlank(nextError)) {
fail(nextError);
}
}
} finally {
pool.shutdown();
}
}
@Test
@Ignore
public void testCreateBuiltInProfiles() throws Exception {
@ -523,7 +540,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
@Test
public void testCreateDifferentTypesWithSameForcedId() {
String idName = "forcedId";
@ -544,7 +560,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
obs = myObservationDao.read(obsId.toUnqualifiedVersionless(), mySrd);
}
@Test
public void testCreateDuplicateTagsDoesNotCauseDuplicates() {
Patient p = new Patient();
@ -853,7 +868,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
}
@Test
public void testCreateWithInvalidReferenceFailsGracefully() {
Patient patient = new Patient();
@ -1108,49 +1122,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
@Test
public void testDeleteTwicePerformsNoOp() {
Patient patient = new Patient();
patient.setActive(true);
IIdType id = myPatientDao.create(patient, mySrd).getId();
assertNotNull(id.getIdPartAsLong());
assertEquals("1", id.getVersionIdPart());
IIdType id2 = myPatientDao.delete(id.toUnqualifiedVersionless()).getId();
assertEquals(id.getIdPart(), id2.getIdPart());
assertEquals("2", id2.getVersionIdPart());
IIdType id3 = myPatientDao.delete(id.toUnqualifiedVersionless()).getId();
assertEquals(id.getIdPart(), id3.getIdPart());
assertEquals("2", id3.getVersionIdPart());
IIdType id4 = myPatientDao.delete(id.toUnqualifiedVersionless()).getId();
assertEquals(id.getIdPart(), id4.getIdPart());
assertEquals("2", id4.getVersionIdPart());
patient = new Patient();
patient.setId(id.getIdPart());
patient.setActive(false);
IIdType id5 = myPatientDao.update(patient).getId();
assertEquals(id.getIdPart(), id5.getIdPart());
assertEquals("3", id5.getVersionIdPart());
patient = myPatientDao.read(id.withVersion("1"));
assertEquals(true, patient.getActive());
try {
myPatientDao.read(id.withVersion("2"));
fail();
} catch (ResourceGoneException e) {
// good
}
patient = myPatientDao.read(id.withVersion("3"));
assertEquals(false, patient.getActive());
}
@Test
public void testDeleteResource() {
int initialHistory = myPatientDao.history(null, null, mySrd).size();
@ -1215,6 +1186,29 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
/**
* See #773
*/
@Test
public void testDeleteResourceWithOutboundDeletedResources() {
myDaoConfig.setEnforceReferentialIntegrityOnDelete(false);
Organization org = new Organization();
org.setId("ORG");
org.setName("ORG");
myOrganizationDao.update(org);
Patient pat = new Patient();
pat.setId("PAT");
pat.setActive(true);
pat.setManagingOrganization(new Reference("Organization/ORG"));
myPatientDao.update(pat);
myOrganizationDao.delete(new IdType("Organization/ORG"));
myPatientDao.delete(new IdType("Patient/PAT"));
}
@Test
public void testDeleteThenUndelete() {
Patient patient = new Patient();
@ -1248,6 +1242,49 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
assertEquals(id2, gotId);
}
@Test
public void testDeleteTwicePerformsNoOp() {
Patient patient = new Patient();
patient.setActive(true);
IIdType id = myPatientDao.create(patient, mySrd).getId();
assertNotNull(id.getIdPartAsLong());
assertEquals("1", id.getVersionIdPart());
IIdType id2 = myPatientDao.delete(id.toUnqualifiedVersionless()).getId();
assertEquals(id.getIdPart(), id2.getIdPart());
assertEquals("2", id2.getVersionIdPart());
IIdType id3 = myPatientDao.delete(id.toUnqualifiedVersionless()).getId();
assertEquals(id.getIdPart(), id3.getIdPart());
assertEquals("2", id3.getVersionIdPart());
IIdType id4 = myPatientDao.delete(id.toUnqualifiedVersionless()).getId();
assertEquals(id.getIdPart(), id4.getIdPart());
assertEquals("2", id4.getVersionIdPart());
patient = new Patient();
patient.setId(id.getIdPart());
patient.setActive(false);
IIdType id5 = myPatientDao.update(patient).getId();
assertEquals(id.getIdPart(), id5.getIdPart());
assertEquals("3", id5.getVersionIdPart());
patient = myPatientDao.read(id.withVersion("1"));
assertEquals(true, patient.getActive());
try {
myPatientDao.read(id.withVersion("2"));
fail();
} catch (ResourceGoneException e) {
// good
}
patient = myPatientDao.read(id.withVersion("3"));
assertEquals(false, patient.getActive());
}
@Test
public void testDeleteWithHas() {
Observation obs1 = new Observation();
@ -2851,6 +2888,21 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
assertEquals(BundleEntrySearchModeEnum.INCLUDE.getCode(), ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get((IAnyResource) results.get(1)));
}
@Test
public void testSaveAndReturnCollectionBundle() throws IOException {
String input = IOUtils.toString(FhirResourceDaoR4Test.class.getResourceAsStream("/r4/collection-bundle.json"));
Bundle inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
myBundleDao.update(inputBundle);
Bundle outputBundle = myBundleDao.read(new IdType("cftest"));
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outputBundle));
for (BundleEntryComponent next : outputBundle.getEntry()) {
assertTrue(next.getResource().getIdElement().hasIdPart());
}
}
@Test()
public void testSortByComposite() {
Observation o = new Observation();
@ -2920,6 +2972,40 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
}
@Test
@Ignore
public void testSortByEncounterLength() {
String methodName = "testSortByNumber";
Encounter e1 = new Encounter();
e1.addIdentifier().setSystem("foo").setValue(methodName);
e1.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("min").setValue(4.0 * 24 * 60);
IIdType id1 = myEncounterDao.create(e1, mySrd).getId().toUnqualifiedVersionless();
Encounter e3 = new Encounter();
e3.addIdentifier().setSystem("foo").setValue(methodName);
e3.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("year").setValue(3.0);
IIdType id3 = myEncounterDao.create(e3, mySrd).getId().toUnqualifiedVersionless();
Encounter e2 = new Encounter();
e2.addIdentifier().setSystem("foo").setValue(methodName);
e2.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("year").setValue(2.0);
IIdType id2 = myEncounterDao.create(e2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap pm;
List<String> actual;
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH));
actual = toUnqualifiedVersionlessIdValues(myEncounterDao.search(pm));
assertThat(actual, contains(toValues(id1, id2, id3)));
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH, SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIdValues(myEncounterDao.search(pm));
assertThat(actual, contains(toValues(id3, id2, id1)));
}
@Test
public void testSortById() {
String methodName = "testSortBTyId";
@ -3053,41 +3139,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
assertThat(actual, contains(toValues(id3, id2, id1)));
}
@Test
@Ignore
public void testSortByEncounterLength() {
String methodName = "testSortByNumber";
Encounter e1 = new Encounter();
e1.addIdentifier().setSystem("foo").setValue(methodName);
e1.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("min").setValue(4.0 * 24 * 60);
IIdType id1 = myEncounterDao.create(e1, mySrd).getId().toUnqualifiedVersionless();
Encounter e3 = new Encounter();
e3.addIdentifier().setSystem("foo").setValue(methodName);
e3.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("year").setValue(3.0);
IIdType id3 = myEncounterDao.create(e3, mySrd).getId().toUnqualifiedVersionless();
Encounter e2 = new Encounter();
e2.addIdentifier().setSystem("foo").setValue(methodName);
e2.getLength().setSystem(BaseHapiFhirDao.UCUM_NS).setCode("year").setValue(2.0);
IIdType id2 = myEncounterDao.create(e2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap pm;
List<String> actual;
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH));
actual = toUnqualifiedVersionlessIdValues(myEncounterDao.search(pm));
assertThat(actual, contains(toValues(id1, id2, id3)));
pm = new SearchParameterMap();
pm.setSort(new SortSpec(Encounter.SP_LENGTH, SortOrderEnum.DESC));
actual = toUnqualifiedVersionlessIdValues(myEncounterDao.search(pm));
assertThat(actual, contains(toValues(id3, id2, id1)));
}
public void testSortByQuantity() {
Observation res;

View File

@ -6,6 +6,7 @@ import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
@ -58,18 +59,16 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.demo;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
@ -59,18 +60,16 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -55,18 +55,16 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -3,6 +3,7 @@ package ca.uhn.fhirtest.config;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
@ -12,7 +13,6 @@ import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
@ -92,7 +92,7 @@ public class TdlDstu2Config extends BaseJavaConfigDstu2 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu2");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
@ -103,7 +103,7 @@ public class TdlDstu2Config extends BaseJavaConfigDstu2 {
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -1,14 +1,18 @@
package ca.uhn.fhirtest.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
@ -21,15 +25,9 @@ import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@Import(CommonConfig.class)
@ -74,18 +72,16 @@ public class TdlDstu3Config extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu3");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");

View File

@ -3,15 +3,14 @@ package ca.uhn.fhirtest.config;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.dialect.PostgreSQL94Dialect;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -95,11 +94,9 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu2");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -107,7 +104,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
private Properties jpaProperties() {
Properties extraProperties = new Properties();
if (CommonConfig.isLocalTestMode()) {
extraProperties.put("hibernate.dialect", DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
} else {
extraProperties.put("hibernate.dialect", PostgreSQL94Dialect.class.getName());
}

View File

@ -1,31 +1,32 @@
package ca.uhn.fhirtest.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.dialect.PostgreSQL94Dialect;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@Import(CommonConfig.class)
@ -92,11 +93,9 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu3");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -104,7 +103,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
private Properties jpaProperties() {
Properties extraProperties = new Properties();
if (CommonConfig.isLocalTestMode()) {
extraProperties.put("hibernate.dialect", DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
} else {
extraProperties.put("hibernate.dialect", PostgreSQL94Dialect.class.getName());
}

View File

@ -1,31 +1,32 @@
package ca.uhn.fhirtest.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.dialect.DerbyTenSevenDialect;
import org.hibernate.dialect.PostgreSQL94Dialect;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@Import(CommonConfig.class)
@ -87,11 +88,9 @@ public class TestR4Config extends BaseJavaConfigR4 {
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName("PU_HapiFhirJpaR4");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
@ -99,7 +98,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
private Properties jpaProperties() {
Properties extraProperties = new Properties();
if (CommonConfig.isLocalTestMode()) {
extraProperties.put("hibernate.dialect", DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
} else {
extraProperties.put("hibernate.dialect", PostgreSQL94Dialect.class.getName());
}

View File

@ -48,7 +48,7 @@
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect" />
</bean>
</property>
</bean>

View File

@ -145,6 +145,11 @@
The HAPI FHIR CLI now supports importing an IGPack file as an import
to the validation process.
</action>
<action type="add">
When two threads attempt to update the same resource at the same time, previously
an unspecified error was thrown by the JPA server. An HTTP 412
(Precondition Failed) with an informative error message is now thrown.
</action>
</release>
<release version="3.3.0" date="2018-03-29">
<action type="add">