Merge branch 'master' into OWASPprofile

This commit is contained in:
Patrick Werner 2018-03-28 14:56:55 +02:00 committed by GitHub
commit eac66323be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 241 additions and 50 deletions

View File

@ -224,13 +224,17 @@
</pluginManagement>
<plugins>
<!-- Tell Maven which Java source version you want to use -->
<!--
The CQF-Ruler project has some OWASP dependency security failures which we don't want
to cause the whole build to fail. TODO: investigate these
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<failBuildOnCVSS>99</failBuildOnCVSS>
<failOnError>false</failOnError>
</configuration>
</plugin>

View File

@ -20,29 +20,32 @@ package ca.uhn.fhir.jpa.dao;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.param.DateRangeParam;
import org.hl7.fhir.instance.model.api.IBaseResource;
import javax.persistence.EntityManager;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.param.DateRangeParam;
public interface ISearchBuilder {
Iterator<Long> createQuery(SearchParameterMap theParams, String theSearchUuid);
void setType(Class<? extends IBaseResource> theResourceType, String theResourceName);
void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation, EntityManager theEntityManager,
FhirContext theContext, IDao theDao);
Set<Long> loadReverseIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode,
DateRangeParam theLastUpdated);
/**
* How many results may be fetched at once
*/
void setFetchSize(int theFetchSize);
void setType(Class<? extends IBaseResource> theResourceType, String theResourceName);
}

View File

@ -59,6 +59,9 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.internal.SessionImpl;
import org.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -104,6 +107,7 @@ public class SearchBuilder implements ISearchBuilder {
private ISearchParamRegistry mySearchParamRegistry;
private String mySearchUuid;
private IHapiTerminologySvc myTerminologySvc;
private int myFetchSize;
/**
* Constructor
@ -1926,6 +1930,11 @@ public class SearchBuilder implements ISearchBuilder {
}
}
@Override
public void setFetchSize(int theFetchSize) {
myFetchSize = theFetchSize;
}
@Override
public void setType(Class<? extends IBaseResource> theResourceType, String theResourceName) {
myResourceType = theResourceType;
@ -2181,6 +2190,7 @@ public class SearchBuilder implements ISearchBuilder {
final TypedQuery<Long> query = createQuery(mySort, maximumResults);
Query<Long> hibernateQuery = (Query<Long>) query;
hibernateQuery.setFetchSize(myFetchSize);
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
myResultsIterator = new ScrollableResultsIterator(scroll);

View File

@ -206,6 +206,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
sb.setType(resourceTypeClass, theResourceType);
sb.setFetchSize(mySyncSize);
final Integer loadSynchronousUpTo;
if (theCacheControlDirective != null && theCacheControlDirective.isNoStore()) {
@ -233,7 +234,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
public SimpleBundleProvider doInTransaction(TransactionStatus theStatus) {
// Load the results synchronously
final List<Long> pids = new ArrayList<Long>();
final List<Long> pids = new ArrayList<>();
Iterator<Long> resultIter = sb.createQuery(theParams, searchUuid);
while (resultIter.hasNext()) {
@ -458,8 +459,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
private final SearchParameterMap myParams;
private final String myResourceType;
private final Search mySearch;
private final ArrayList<Long> mySyncedPids = new ArrayList<Long>();
private final ArrayList<Long> myUnsyncedPids = new ArrayList<Long>();
private final ArrayList<Long> mySyncedPids = new ArrayList<>();
private final ArrayList<Long> myUnsyncedPids = new ArrayList<>();
private boolean myAbortRequested;
private int myCountSaved = 0;
private String mySearchUuid;
@ -503,7 +504,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
* It is called automatically by the thread pool.
*/
@Override
public Void call() throws Exception {
public Void call() {
StopWatch sw = new StopWatch();
try {
@ -631,10 +632,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
boolean keepWaiting;
do {
synchronized (mySyncedPids) {
keepWaiting = false;
if (mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING) {
keepWaiting = true;
}
keepWaiting = mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING;
}
if (keepWaiting) {
ourLog.info("Waiting, as we only have {} results", mySyncedPids.size());

View File

@ -0,0 +1,157 @@
package ca.uhn.fhir.jpa.util;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.engine.spi.SessionImplementor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.LocalEntityManagerFactoryBean;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import java.sql.Connection;
import static org.springframework.orm.jpa.EntityManagerFactoryUtils.ENTITY_MANAGER_SYNCHRONIZATION_ORDER;
import static org.springframework.util.ReflectionUtils.invokeMethod;
/**
* Hibernate's {@link StatelessSession} factory which will be bound to the
* current transaction. This factory returns a Proxy which delegates method
* calls to the underlying {@link StatelessSession} bound to transaction. At the
* end of the transaction the session is automatically closed. This class
* borrows idea's from {@link DataSourceUtils},
* {@link EntityManagerFactoryUtils}, {@link ResourceHolderSynchronization} and
* {@link LocalEntityManagerFactoryBean}.
*/
public class StatelessSessionFactoryBean implements FactoryBean<StatelessSession> {
private SessionFactory sessionFactory;
@Autowired
public StatelessSessionFactoryBean(SessionFactory theSessionFactory) {
this.sessionFactory = theSessionFactory;
}
@Override
public StatelessSession getObject() throws Exception {
StatelessSessionInterceptor statelessSessionInterceptor = new StatelessSessionInterceptor(
sessionFactory);
return ProxyFactory.getProxy(StatelessSession.class, statelessSessionInterceptor);
}
@Override
public Class<?> getObjectType() {
return StatelessSession.class;
}
@Override
public boolean isSingleton() {
return true;
}
/**
* Use this to override the {@link SessionFactory} obtained from the
* {@link EntityManagerFactory}. Please note that the connection will still
* be used from the {@link EntityManager}.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private static class StatelessSessionInterceptor implements MethodInterceptor {
private final SessionFactory sessionFactory;
public StatelessSessionInterceptor(
SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private void bindWithTransaction(StatelessSession statelessSession) {
TransactionSynchronizationManager
.registerSynchronization(new StatelessSessionSynchronization(sessionFactory,
statelessSession));
TransactionSynchronizationManager.bindResource(sessionFactory, statelessSession);
}
private StatelessSession getCurrentSession() {
if (!TransactionSynchronizationManager.isActualTransactionActive()) {
throw new IllegalStateException(
"There should be an active transaction for the current thread.");
}
StatelessSession statelessSession = (StatelessSession) TransactionSynchronizationManager
.getResource(sessionFactory);
if (statelessSession == null) {
statelessSession = openNewStatelessSession();
bindWithTransaction(statelessSession);
}
return statelessSession;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
StatelessSession statelessSession = getCurrentSession();
return invokeMethod(invocation.getMethod(), statelessSession, invocation.getArguments());
}
/**
* It is important we obtain the physical (real) connection otherwise it
* will be double proxied and there will be problems releasing the
* connection.
*/
private Connection obtainPhysicalConnection() {
EntityManager entityManager = EntityManagerFactoryUtils
.getTransactionalEntityManager(sessionFactory);
SessionImplementor sessionImplementor = (SessionImplementor) entityManager
.getDelegate();
// return sessionImplementor.getTransactionCoordinator().getJdbcCoordinator()
// .getLogicalConnection().getConnection();
return null;
}
private StatelessSession openNewStatelessSession() {
Connection connection = obtainPhysicalConnection();
return sessionFactory.openStatelessSession(connection);
}
}
private static class StatelessSessionSynchronization extends TransactionSynchronizationAdapter {
private final SessionFactory sessionFactory;
private final StatelessSession statelessSession;
public StatelessSessionSynchronization(SessionFactory sessionFactory,
StatelessSession statelessSession) {
this.sessionFactory = sessionFactory;
this.statelessSession = statelessSession;
}
@Override
public void beforeCommit(boolean readOnly) {
if (!readOnly) {
// ((TransactionContext) statelessSession).flu
}
}
@Override
public void beforeCompletion() {
TransactionSynchronizationManager.unbindResource(sessionFactory);
statelessSession.close();
}
@Override
public int getOrder() {
return ENTITY_MANAGER_SYNCHRONIZATION_ORDER - 100;
}
}
}

View File

@ -68,6 +68,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu2");
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
retVal.setFetchSizeDefaultMaximum(10000);
return retVal;
}

View File

@ -57,6 +57,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu3");
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
retVal.setFetchSizeDefaultMaximum(10000);
return retVal;
}

View File

@ -58,6 +58,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseR4");
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
retVal.setFetchSizeDefaultMaximum(10000);
return retVal;
}

View File

@ -7,7 +7,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>3.3.0-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<groupId>ca.uhn.hapi.fhir.karaf</groupId>

View File

@ -21,7 +21,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>3.3.0-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-karaf-integration-tests</artifactId>

50
pom.xml
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.sonatype.oss</groupId>
@ -1320,7 +1321,8 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>
jacoco-maven-plugin</artifactId>
jacoco-maven-plugin
</artifactId>
<version>0.7.9</version>
</plugin>
<plugin>
@ -1568,7 +1570,9 @@
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken>http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css</replacetoken>
<replacetoken>
http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css
</replacetoken>
<replacevalue>./css/bootstrap-responsive.min.css</replacevalue>
</replace>
<replace dir="target/site" summary="true">
@ -1578,8 +1582,10 @@
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken>http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css</replacetoken>
<replacevalue>https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css</replacevalue>
<replacetoken>http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
</replacetoken>
<replacevalue>https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
</replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
@ -1623,28 +1629,35 @@
<echo>Adding Fontawesome</echo>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[<a href="download.html" title="Download">Download</a>]]></replacetoken>
<replacevalue><![CDATA[<a href="download.html" title="Download"><i class="fa fa-download"></i> Download</a>]]></replacevalue>
<replacetoken>
<![CDATA[<a href="download.html" title="Download">Download</a>]]></replacetoken>
<replacevalue>
<![CDATA[<a href="download.html" title="Download"><i class="fa fa-download"></i> Download</a>]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink">GitHub Project</a>]]></replacetoken>
<replacevalue><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink"><i class="fa fa-github"></i> GitHub Project</a>]]></replacevalue>
<replacetoken>
<![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink">GitHub Project</a>]]></replacetoken>
<replacevalue>
<![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink"><i class="fa fa-github"></i> GitHub Project</a>]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Test Servers <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-fire"></i>&nbsp;Test Servers&nbsp;<]]></replacevalue>
<replacevalue>
<![CDATA[data-toggle="dropdown"><i class="fa fa-fire"></i>&nbsp;Test Servers&nbsp;<]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Documentation <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-book"></i>&nbsp;Documentation&nbsp;<]]></replacevalue>
<replacevalue>
<![CDATA[data-toggle="dropdown"><i class="fa fa-book"></i>&nbsp;Documentation&nbsp;<]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Get Help <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-support"></i>&nbsp;Get Help&nbsp;<]]></replacevalue>
<replacevalue>
<![CDATA[data-toggle="dropdown"><i class="fa fa-support"></i>&nbsp;Get Help&nbsp;<]]></replacevalue>
</replace>
<echo>Changing Breadcrumbs</echo>
<replace dir="target/site" summary="true">
@ -1860,9 +1873,12 @@
<configuration>
<reportsDirectories>
<reportDirectory>${project.basedir}/hapi-fhir-base/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu2/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-jpaserver-base/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu/target/surefire-reports/
</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu2/target/surefire-reports/
</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-jpaserver-base/target/surefire-reports/
</reportDirectory>
</reportsDirectories>
</configuration>
</plugin>
@ -1977,8 +1993,6 @@
<module>hapi-tinder-plugin</module>
<module>hapi-tinder-test</module>
<module>hapi-fhir-client</module>
<module>hapi-fhir-karaf-features</module>
<module>hapi-fhir-karaf-integration-tests</module>
<module>hapi-fhir-server</module>
<module>hapi-fhir-validation</module>
<!--<module>hapi-fhir-narrativegenerator</module>-->
@ -2006,6 +2020,8 @@
<module>hapi-fhir-cli</module>
<module>hapi-fhir-dist</module>
<module>examples</module>
<module>osgi/hapi-fhir-karaf-features</module>
<module>osgi/hapi-fhir-karaf-integration-tests</module>
<module>example-projects/hapi-fhir-base-example-embedded-ws</module>
<module>example-projects/hapi-fhir-standalone-overlay-example</module>
<module>example-projects/hapi-fhir-jpaserver-cds-example</module>