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> </pluginManagement>
<plugins> <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> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.owasp</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>dependency-check-maven</artifactId>
<configuration> <configuration>
<source>1.7</source> <failBuildOnCVSS>99</failBuildOnCVSS>
<target>1.7</target> <failOnError>false</failOnError>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,29 +20,32 @@ package ca.uhn.fhir.jpa.dao;
* #L% * #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.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; 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 { public interface ISearchBuilder {
Iterator<Long> createQuery(SearchParameterMap theParams, String theSearchUuid); 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, void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation, EntityManager theEntityManager,
FhirContext theContext, IDao theDao); FhirContext theContext, IDao theDao);
Set<Long> loadReverseIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode, Set<Long> loadReverseIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode,
DateRangeParam theLastUpdated); 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.apache.commons.lang3.tuple.Pair;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; 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.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.BaseResource; import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
@ -104,6 +107,7 @@ public class SearchBuilder implements ISearchBuilder {
private ISearchParamRegistry mySearchParamRegistry; private ISearchParamRegistry mySearchParamRegistry;
private String mySearchUuid; private String mySearchUuid;
private IHapiTerminologySvc myTerminologySvc; private IHapiTerminologySvc myTerminologySvc;
private int myFetchSize;
/** /**
* Constructor * Constructor
@ -1926,6 +1930,11 @@ public class SearchBuilder implements ISearchBuilder {
} }
} }
@Override
public void setFetchSize(int theFetchSize) {
myFetchSize = theFetchSize;
}
@Override @Override
public void setType(Class<? extends IBaseResource> theResourceType, String theResourceName) { public void setType(Class<? extends IBaseResource> theResourceType, String theResourceName) {
myResourceType = theResourceType; myResourceType = theResourceType;
@ -2181,6 +2190,7 @@ public class SearchBuilder implements ISearchBuilder {
final TypedQuery<Long> query = createQuery(mySort, maximumResults); final TypedQuery<Long> query = createQuery(mySort, maximumResults);
Query<Long> hibernateQuery = (Query<Long>) query; Query<Long> hibernateQuery = (Query<Long>) query;
hibernateQuery.setFetchSize(myFetchSize);
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY); ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
myResultsIterator = new ScrollableResultsIterator(scroll); myResultsIterator = new ScrollableResultsIterator(scroll);

View File

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

View File

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

View File

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

View File

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

View File

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

58
pom.xml
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <parent>
<groupId>org.sonatype.oss</groupId> <groupId>org.sonatype.oss</groupId>
@ -609,7 +610,7 @@
<groupId>es.nitaur.markdown</groupId> <groupId>es.nitaur.markdown</groupId>
<artifactId>txtmark</artifactId> <artifactId>txtmark</artifactId>
<version>0.16</version> <version>0.16</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.ejb</groupId> <groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId> <artifactId>ejb-api</artifactId>
@ -676,9 +677,9 @@
<version>2.0.1</version> <version>2.0.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.12</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>lt.velykis.maven.skins</groupId> <groupId>lt.velykis.maven.skins</groupId>
@ -1320,7 +1321,8 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId> <artifactId>
jacoco-maven-plugin</artifactId> jacoco-maven-plugin
</artifactId>
<version>0.7.9</version> <version>0.7.9</version>
</plugin> </plugin>
<plugin> <plugin>
@ -1568,7 +1570,9 @@
</replace> </replace>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <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> <replacevalue>./css/bootstrap-responsive.min.css</replacevalue>
</replace> </replace>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
@ -1578,8 +1582,10 @@
</replace> </replace>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
<replacetoken>http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css</replacetoken> <replacetoken>http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
<replacevalue>https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css</replacevalue> </replacetoken>
<replacevalue>https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
</replacevalue>
</replace> </replace>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
@ -1623,28 +1629,35 @@
<echo>Adding Fontawesome</echo> <echo>Adding Fontawesome</echo>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
<replacetoken><![CDATA[<a href="download.html" title="Download">Download</a>]]></replacetoken> <replacetoken>
<replacevalue><![CDATA[<a href="download.html" title="Download"><i class="fa fa-download"></i> Download</a>]]></replacevalue> <![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>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
<replacetoken><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink">GitHub Project</a>]]></replacetoken> <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> <![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>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Test Servers <]]></replacetoken> <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>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Documentation <]]></replacetoken> <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>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
<include name="*.html"/> <include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Get Help <]]></replacetoken> <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> </replace>
<echo>Changing Breadcrumbs</echo> <echo>Changing Breadcrumbs</echo>
<replace dir="target/site" summary="true"> <replace dir="target/site" summary="true">
@ -1860,9 +1873,12 @@
<configuration> <configuration>
<reportsDirectories> <reportsDirectories>
<reportDirectory>${project.basedir}/hapi-fhir-base/target/surefire-reports/</reportDirectory> <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-dstu/target/surefire-reports/
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu2/target/surefire-reports/</reportDirectory> </reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-jpaserver-base/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> </reportsDirectories>
</configuration> </configuration>
</plugin> </plugin>
@ -1977,8 +1993,6 @@
<module>hapi-tinder-plugin</module> <module>hapi-tinder-plugin</module>
<module>hapi-tinder-test</module> <module>hapi-tinder-test</module>
<module>hapi-fhir-client</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-server</module>
<module>hapi-fhir-validation</module> <module>hapi-fhir-validation</module>
<!--<module>hapi-fhir-narrativegenerator</module>--> <!--<module>hapi-fhir-narrativegenerator</module>-->
@ -2006,6 +2020,8 @@
<module>hapi-fhir-cli</module> <module>hapi-fhir-cli</module>
<module>hapi-fhir-dist</module> <module>hapi-fhir-dist</module>
<module>examples</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-base-example-embedded-ws</module>
<module>example-projects/hapi-fhir-standalone-overlay-example</module> <module>example-projects/hapi-fhir-standalone-overlay-example</module>
<module>example-projects/hapi-fhir-jpaserver-cds-example</module> <module>example-projects/hapi-fhir-jpaserver-cds-example</module>