Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<properties>
<java.version>17</java.version>
<hapi.fhir.jpa.server.starter.revision>2</hapi.fhir.jpa.server.starter.revision>
<hapi.fhir.jpa.server.starter.revision>3</hapi.fhir.jpa.server.starter.revision>
<clinical-reasoning.version>3.26.0</clinical-reasoning.version>
</properties>

Expand Down Expand Up @@ -60,6 +60,16 @@

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>${spring_boot_version}</version>
</dependency>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
</dependency>

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
Expand Down Expand Up @@ -265,12 +275,7 @@
<artifactId>moment</artifactId>
</dependency>

<!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<scope>test</scope>
</dependency>


<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2025 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.jpa.provider;

import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.RawParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;

import java.util.List;
import java.util.Map;

public abstract class BaseJpaResourceProviderObservation<T extends IBaseResource> extends BaseJpaResourceProvider<T> {

/**
* Observation/$lastn
*/
@Operation(name = JpaConstants.OPERATION_LASTN, idempotent = true, bundleType = BundleTypeEnum.SEARCHSET)
public IBundleProvider observationLastN(
jakarta.servlet.http.HttpServletRequest theServletRequest,
jakarta.servlet.http.HttpServletResponse theServletResponse,
ca.uhn.fhir.rest.api.server.RequestDetails theRequestDetails,
@Description(
formalDefinition =
"Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT, typeName = "unsignedInt")
IPrimitiveType<Integer> theCount,
@Description(shortDefinition = "The classification of the type of observation")
@OperationParam(name = "category")
TokenAndListParam theCategory,
@Description(shortDefinition = "The code of the observation type") @OperationParam(name = "code")
TokenAndListParam theCode,
@Description(shortDefinition = "The effective date of the observation") @OperationParam(name = "date")
DateAndListParam theDate,
@Description(shortDefinition = "The subject that the observation is about (if patient)")
@OperationParam(name = "patient")
ReferenceAndListParam thePatient,
@Description(shortDefinition = "The subject that the observation is about")
@OperationParam(name = "subject")
ReferenceAndListParam theSubject,
@Description(shortDefinition = "The maximum number of observations to return for each observation code")
@OperationParam(name = "max", typeName = "integer", min = 0, max = 1)
IPrimitiveType<Integer> theMax,
@RawParam Map<String, List<String>> theAdditionalRawParams) {
startRequest(theServletRequest);
try {
SearchParameterMap paramMap = new SearchParameterMap();
paramMap.add(org.hl7.fhir.r4.model.Observation.SP_CATEGORY, theCategory);
paramMap.add(org.hl7.fhir.r4.model.Observation.SP_CODE, theCode);
paramMap.add(org.hl7.fhir.r4.model.Observation.SP_DATE, theDate);
if (thePatient != null) {
paramMap.add(org.hl7.fhir.r4.model.Observation.SP_PATIENT, thePatient);
}
if (theSubject != null) {
paramMap.add(org.hl7.fhir.r4.model.Observation.SP_SUBJECT, theSubject);
}
if (theMax != null) {
paramMap.setLastNMax(theMax.getValue());

/**
* The removal of the original raw parameter is required as every implementing class
* has the "Observation" resource class defined. For this resource, the max parameter
* is not supported and thus has to be removed before the use of "translateRawParameters".
*/
if (theAdditionalRawParams != null) theAdditionalRawParams.remove("max");
}
if (theCount != null) {
paramMap.setCount(theCount.getValue());
}

getDao().translateRawParameters(theAdditionalRawParams, paramMap);

return ((IFhirResourceDaoObservation<?>) getDao())
.observationsLastN(paramMap, theRequestDetails, theServletResponse);
} finally {
endRequest(theServletRequest);
}
}
}
3 changes: 2 additions & 1 deletion src/main/java/ca/uhn/fhir/jpa/starter/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
import org.springframework.context.annotation.Import;

@ServletComponentScan(basePackageClasses = {RestfulServer.class})
@SpringBootApplication(exclude = {ElasticsearchRestClientAutoConfiguration.class, ThymeleafAutoConfiguration.class})
@SpringBootApplication(exclude = {ThymeleafAutoConfiguration.class})
@Import({
ElasticsearchRestClientAutoConfiguration.class,
StarterCrR4Config.class,
StarterCrDstu3Config.class,
StarterCdsHooksConfig.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ca.uhn.fhir.jpa.starter.annotations;

import ca.uhn.fhir.jpa.starter.AppProperties;
import org.springframework.boot.context.properties.bind.Binder;
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
Expand All @@ -10,9 +10,7 @@ public class OnImplementationGuidesPresent implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {

AppProperties config = Binder.get(conditionContext.getEnvironment())
.bind("hapi.fhir", AppProperties.class)
.orElse(null);
AppProperties config = EnvironmentHelper.getConfiguration(conditionContext, "hapi.fhir", AppProperties.class);
if (config == null) return false;
if (config.getImplementationGuides() == null) return false;
return !config.getImplementationGuides().isEmpty();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
import ca.uhn.fhir.jpa.starter.AppProperties;
import ca.uhn.fhir.jpa.starter.elastic.ElasticsearchBootSvcImpl;
import ca.uhn.fhir.jpa.starter.util.JpaHibernatePropertiesProvider;
import ca.uhn.fhir.jpa.subscription.match.deliver.email.EmailSenderImpl;
import ca.uhn.fhir.jpa.subscription.match.deliver.email.IEmailSender;
Expand All @@ -19,10 +20,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.*;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

Expand All @@ -36,6 +34,7 @@
*/
@Configuration
@EnableTransactionManagement
@Import(ElasticsearchBootSvcImpl.class)
public class FhirServerConfigCommon {

private static final Logger ourLog = LoggerFactory.getLogger(FhirServerConfigCommon.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

@Configuration
@Conditional(OnDSTU3Condition.class)
@Import({JpaDstu3Config.class, StarterJpaConfig.class, StarterCrDstu3Config.class, ElasticsearchConfig.class})
@Import({JpaDstu3Config.class, StarterJpaConfig.class, StarterCrDstu3Config.class})
public class FhirServerConfigDstu3 {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,5 @@

@Configuration
@Conditional(OnR4Condition.class)
@Import({
JpaR4Config.class,
StarterJpaConfig.class,
StarterCrR4Config.class,
ElasticsearchConfig.class,
StarterIpsConfig.class
})
@Import({JpaR4Config.class, StarterJpaConfig.class, StarterCrR4Config.class, StarterIpsConfig.class})
public class FhirServerConfigR4 {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

@Configuration
@Conditional(OnR4BCondition.class)
@Import({JpaR4BConfig.class, SubscriptionTopicConfig.class, StarterJpaConfig.class, ElasticsearchConfig.class})
@Import({JpaR4BConfig.class, SubscriptionTopicConfig.class, StarterJpaConfig.class})
public class FhirServerConfigR4B {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

@Configuration
@Conditional(OnR5Condition.class)
@Import({StarterJpaConfig.class, JpaR5Config.class, SubscriptionTopicConfig.class, ElasticsearchConfig.class})
@Import({StarterJpaConfig.class, JpaR5Config.class, SubscriptionTopicConfig.class})
public class FhirServerConfigR5 {}
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package ca.uhn.fhir.jpa.starter.common;

import ca.uhn.fhir.jpa.starter.AppProperties;
import org.springframework.boot.context.properties.bind.Binder;
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class OnPartitionModeEnabled implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
var appProperties = Binder.get(context.getEnvironment())
.bind("hapi.fhir", AppProperties.class)
.orElse(null);
var appProperties = EnvironmentHelper.getConfiguration(context, "hapi.fhir", AppProperties.class);
if (appProperties == null) return false;
return appProperties.getPartitioning() != null;
}
Expand Down
33 changes: 12 additions & 21 deletions src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
import ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory;
import ca.uhn.fhir.jpa.starter.ig.ExtendedPackageInstallationSpec;
import ca.uhn.fhir.jpa.starter.ig.IImplementationGuideOperationProvider;
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.mdm.provider.MdmProviderLoader;
Expand Down Expand Up @@ -83,23 +82,21 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.http.HttpHeaders;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.web.cors.CorsConfiguration;

import java.io.IOException;
import java.util.*;
import javax.sql.DataSource;

Expand All @@ -123,9 +120,6 @@ public IStaleSearchDeletingSvc staleSearchDeletingSvc() {
return new StaleSearchDeletingSvcImpl();
}

@Autowired
private ConfigurableEnvironment configurableEnvironment;

/**
* Customize the default/max page sizes for search results. You can set these however
* you want, although very large page sizes will require a lot of RAM.
Expand All @@ -151,22 +145,20 @@ public ResourceCountCache resourceCountsCache(IFhirSystemDao<?, ?> theSystemDao)
@Primary
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
JpaProperties theJpaProperties,
DataSource myDataSource,
ConfigurableListableBeanFactory myConfigurableListableBeanFactory,
FhirContext theFhirContext,
JpaStorageSettings theStorageSettings) {
LocalContainerEntityManagerFactoryBean retVal = HapiEntityManagerFactoryUtil.newEntityManagerFactory(
myConfigurableListableBeanFactory, theFhirContext, theStorageSettings);
retVal.setPersistenceUnitName("HAPI_PU");

try {
retVal.setDataSource(myDataSource);
} catch (Exception e) {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
}
retVal.setJpaProperties(
EnvironmentHelper.getHibernateProperties(configurableEnvironment, myConfigurableListableBeanFactory));
return retVal;
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean =
HapiEntityManagerFactoryUtil.newEntityManagerFactory(
myConfigurableListableBeanFactory, theFhirContext, theStorageSettings);

entityManagerFactoryBean.setPersistenceUnitName("HAPI_PU");
entityManagerFactoryBean.setJpaPropertyMap(theJpaProperties.getProperties());
entityManagerFactoryBean.setDataSource(myDataSource);

return entityManagerFactoryBean;
}

@Bean
Expand Down Expand Up @@ -213,8 +205,7 @@ public IPackageInstallerSvc packageInstaller(
Batch2JobRegisterer batch2JobRegisterer,
FhirContext fhirContext,
TransactionProcessor transactionProcessor,
IHapiPackageCacheManager iHapiPackageCacheManager)
throws IOException {
IHapiPackageCacheManager iHapiPackageCacheManager) {

batch2JobRegisterer.start();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ca.uhn.fhir.jpa.starter.common.validation;

import ca.uhn.fhir.jpa.starter.AppProperties;
import org.springframework.boot.context.properties.bind.Binder;
import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
Expand All @@ -10,9 +10,8 @@ public class OnRemoteTerminologyPresent implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {

AppProperties config = Binder.get(conditionContext.getEnvironment())
.bind("hapi.fhir", AppProperties.class)
.orElse(null);
AppProperties config = EnvironmentHelper.getConfiguration(conditionContext, "hapi.fhir", AppProperties.class);

if (config == null) return false;
if (config.getRemoteTerminologyServicesMap() == null) return false;
return !config.getRemoteTerminologyServicesMap().isEmpty();
Expand Down
Loading
Loading