Avoid tag definition constraint (#2620)

* Avoid tag definition constraint failure

* Version bumps

* Add changelog

* Avoid guava issue

* Test fix

* Test fix

* Bump pom
This commit is contained in:
James Agnew 2021-05-01 17:16:15 -04:00 committed by GitHub
parent 55ef6f8653
commit 970a9884f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 439 additions and 3682 deletions

View File

@ -79,7 +79,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1.1</version>
<version>30.1.1-jre</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -3,14 +3,14 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -83,13 +83,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-subscription</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -106,7 +106,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<classifier>classes</classifier>
</dependency>
<dependency>

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 2620
title: "When creating resources in a JPA server under highly concurrent conditions, creating a new
tag across multiple threads could result in a race condition leaving an invalid entry in the
tag cache. This resulted in new instances of this tag being unavailable for creation."

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 2620
title: "In the JPA server, if a tag was defined with the exact same system and code as a security
label on a different resource, the tag would be incorrectly filed as a security label (and
vice versa). This has been corrected."

View File

@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -61,8 +61,6 @@ import java.util.Set;
*/
public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
void addTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel, RequestDetails theRequest);
/**
* Create a resource - Note that this variant of the method does not take in a {@link RequestDetails} and
* therefore can not fire any interceptors. Use only for internal system calls

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -113,7 +113,10 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
@ -179,6 +182,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
private static final Logger ourLog = LoggerFactory.getLogger(BaseHapiFhirDao.class);
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<>();
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
public static final String XACT_USERDATA_KEY_RESOLVED_TAG_DEFINITIONS = BaseHapiFhirDao.class.getName() + "_RESOLVED_TAG_DEFINITIONS";
private static boolean ourValidationDisabledForUnitTest;
private static boolean ourDisableIncrementOnUpdateForUnitTest = false;
@ -287,11 +291,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
return retVal;
}
private void extractTagsHapi(IResource theResource, ResourceTable theEntity, Set<ResourceTag> allDefs) {
private void extractTagsHapi(TransactionDetails theTransactionDetails, IResource theResource, ResourceTable theEntity, Set<ResourceTag> allDefs) {
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
if (tagList != null) {
for (Tag next : tagList) {
TagDefinition def = getTagOrNull(TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
if (def != null) {
ResourceTag tag = theEntity.addTag(def);
allDefs.add(tag);
@ -303,7 +307,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
List<BaseCodingDt> securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(theResource);
if (securityLabels != null) {
for (BaseCodingDt next : securityLabels) {
TagDefinition def = getTagOrNull(TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
if (def != null) {
ResourceTag tag = theEntity.addTag(def);
allDefs.add(tag);
@ -315,7 +319,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
List<IdDt> profiles = ResourceMetadataKeyEnum.PROFILES.get(theResource);
if (profiles != null) {
for (IIdType next : profiles) {
TagDefinition def = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
if (def != null) {
ResourceTag tag = theEntity.addTag(def);
allDefs.add(tag);
@ -325,11 +329,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
}
}
private void extractTagsRi(IAnyResource theResource, ResourceTable theEntity, Set<ResourceTag> theAllTags) {
private void extractTagsRi(TransactionDetails theTransactionDetails, IAnyResource theResource, ResourceTable theEntity, Set<ResourceTag> theAllTags) {
List<? extends IBaseCoding> tagList = theResource.getMeta().getTag();
if (tagList != null) {
for (IBaseCoding next : tagList) {
TagDefinition def = getTagOrNull(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
if (def != null) {
ResourceTag tag = theEntity.addTag(def);
theAllTags.add(tag);
@ -341,7 +345,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
List<? extends IBaseCoding> securityLabels = theResource.getMeta().getSecurity();
if (securityLabels != null) {
for (IBaseCoding next : securityLabels) {
TagDefinition def = getTagOrNull(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
if (def != null) {
ResourceTag tag = theEntity.addTag(def);
theAllTags.add(tag);
@ -353,7 +357,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
List<? extends IPrimitiveType<String>> profiles = theResource.getMeta().getProfile();
if (profiles != null) {
for (IPrimitiveType<String> next : profiles) {
TagDefinition def = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
TagDefinition def = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
if (def != null) {
ResourceTag tag = theEntity.addTag(def);
theAllTags.add(tag);
@ -408,42 +412,56 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
/**
* <code>null</code> will only be returned if the scheme and tag are both blank
*/
protected TagDefinition getTagOrNull(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
protected TagDefinition getTagOrNull(TransactionDetails theTransactionDetails, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
if (isBlank(theScheme) && isBlank(theTerm) && isBlank(theLabel)) {
return null;
}
Pair<String, String> key = Pair.of(theScheme, theTerm);
return myMemoryCacheService.get(MemoryCacheService.CacheEnum.TAG_DEFINITION, key, k -> {
MemoryCacheService.TagDefinitionCacheKey key = toTagDefinitionMemoryCacheKey(theTagType, theScheme, theTerm);
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<TagDefinition> cq = builder.createQuery(TagDefinition.class);
Root<TagDefinition> from = cq.from(TagDefinition.class);
if (isNotBlank(theScheme)) {
cq.where(
builder.and(
builder.equal(from.get("myTagType"), theTagType),
builder.equal(from.get("mySystem"), theScheme),
builder.equal(from.get("myCode"), theTerm)));
} else {
cq.where(
builder.and(
builder.equal(from.get("myTagType"), theTagType),
builder.isNull(from.get("mySystem")),
builder.equal(from.get("myCode"), theTerm)));
TagDefinition retVal = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.TAG_DEFINITION, key);
if (retVal == null) {
HashMap<MemoryCacheService.TagDefinitionCacheKey, TagDefinition> resolvedTagDefinitions = theTransactionDetails.getOrCreateUserData(XACT_USERDATA_KEY_RESOLVED_TAG_DEFINITIONS, () -> new HashMap<>());
retVal = resolvedTagDefinitions.get(key);
if (retVal == null) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<TagDefinition> cq = builder.createQuery(TagDefinition.class);
Root<TagDefinition> from = cq.from(TagDefinition.class);
if (isNotBlank(theScheme)) {
cq.where(
builder.and(
builder.equal(from.get("myTagType"), theTagType),
builder.equal(from.get("mySystem"), theScheme),
builder.equal(from.get("myCode"), theTerm)));
} else {
cq.where(
builder.and(
builder.equal(from.get("myTagType"), theTagType),
builder.isNull(from.get("mySystem")),
builder.equal(from.get("myCode"), theTerm)));
}
TypedQuery<TagDefinition> q = myEntityManager.createQuery(cq);
try {
retVal = q.getSingleResult();
} catch (NoResultException e) {
retVal = new TagDefinition(theTagType, theScheme, theTerm, theLabel);
myEntityManager.persist(retVal);
}
TransactionSynchronization sync = new AddTagDefinitionToCacheAfterCommitSynchronization(key, retVal);
TransactionSynchronizationManager.registerSynchronization(sync);
resolvedTagDefinitions.put(key, retVal);
}
}
TypedQuery<TagDefinition> q = myEntityManager.createQuery(cq);
try {
return q.getSingleResult();
} catch (NoResultException e) {
TagDefinition retVal = new TagDefinition(theTagType, theScheme, theTerm, theLabel);
myEntityManager.persist(retVal);
return retVal;
}
});
return retVal;
}
protected IBundleProvider history(RequestDetails theRequest, String theResourceType, Long theResourcePid, Date theRangeStartInclusive, Date theRangeEndInclusive) {
@ -500,7 +518,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
/**
* Returns true if the resource has changed (either the contents or the tags)
*/
protected EncodedResource populateResourceIntoEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, boolean thePerformIndexing) {
protected EncodedResource populateResourceIntoEntity(TransactionDetails theTransactionDetails, RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, boolean thePerformIndexing) {
if (theEntity.getResourceType() == null) {
theEntity.setResourceType(toResourceName(theResource));
}
@ -522,7 +540,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
IBaseMetaType meta = theResource.getMeta();
boolean hasExtensions = false;
IBaseExtension<?,?> sourceExtension = null;
IBaseExtension<?, ?> sourceExtension = null;
if (meta instanceof IBaseHasExtensions) {
List<? extends IBaseExtension<?, ?>> extensions = ((IBaseHasExtensions) meta).getExtension();
if (!extensions.isEmpty()) {
@ -590,16 +608,16 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
Set<ResourceTag> allTagsOld = getAllTagDefinitions(theEntity);
if (theResource instanceof IResource) {
extractTagsHapi((IResource) theResource, theEntity, allDefs);
extractTagsHapi(theTransactionDetails, (IResource) theResource, theEntity, allDefs);
} else {
extractTagsRi((IAnyResource) theResource, theEntity, allDefs);
extractTagsRi(theTransactionDetails, (IAnyResource) theResource, theEntity, allDefs);
}
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
if (def.isStandardType() == false) {
String profile = def.getResourceProfile("");
if (isNotBlank(profile)) {
TagDefinition profileDef = getTagOrNull(TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null);
TagDefinition profileDef = getTagOrNull(theTransactionDetails, TagTypeEnum.PROFILE, NS_JPA_PROFILE, profile, null);
ResourceTag tag = theEntity.addTag(profileDef);
allDefs.add(tag);
@ -1111,7 +1129,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
entity.setContentText(null);
entity.setHashSha256(null);
entity.setIndexStatus(INDEX_STATUS_INDEXED);
changed = populateResourceIntoEntity(theRequest, theResource, entity, true);
changed = populateResourceIntoEntity(theTransactionDetails, theRequest, theResource, entity, true);
} else {
// CREATE or UPDATE
@ -1123,7 +1141,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
newParams = new ResourceIndexedSearchParams();
mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, theTransactionDetails, entity, theResource, existingParams, theRequest);
changed = populateResourceIntoEntity(theRequest, theResource, entity, true);
changed = populateResourceIntoEntity(theTransactionDetails, theRequest, theResource, entity, true);
if (changed.isChanged()) {
entity.setUpdated(theTransactionDetails.getTransactionDate());
if (theResource instanceof IResource) {
@ -1142,7 +1160,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
} else {
changed = populateResourceIntoEntity(theRequest, theResource, entity, false);
changed = populateResourceIntoEntity(theTransactionDetails, theRequest, theResource, entity, false);
entity.setUpdated(theTransactionDetails.getTransactionDate());
entity.setIndexStatus(null);
@ -1521,6 +1539,27 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
// nothing yet
}
private class AddTagDefinitionToCacheAfterCommitSynchronization implements TransactionSynchronization {
private final TagDefinition myTagDefinition;
private final MemoryCacheService.TagDefinitionCacheKey myKey;
public AddTagDefinitionToCacheAfterCommitSynchronization(MemoryCacheService.TagDefinitionCacheKey theKey, TagDefinition theTagDefinition) {
myTagDefinition = theTagDefinition;
myKey = theKey;
}
@Override
public void afterCommit() {
myMemoryCacheService.put(MemoryCacheService.CacheEnum.TAG_DEFINITION, myKey, myTagDefinition);
}
}
@Nonnull
public static MemoryCacheService.TagDefinitionCacheKey toTagDefinitionMemoryCacheKey(TagTypeEnum theTagType, String theScheme, String theTerm) {
return new MemoryCacheService.TagDefinitionCacheKey(theTagType, theScheme, theTerm);
}
static String cleanProvenanceSourceUri(String theProvenanceSourceUri) {
if (isNotBlank(theProvenanceSourceUri)) {
int hashIndex = theProvenanceSourceUri.indexOf('#');

View File

@ -174,42 +174,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
private IInstanceValidatorModule myInstanceValidator;
private String myResourceName;
private Class<T> myResourceType;
@Autowired
private IRequestPartitionHelperSvc myPartitionHelperSvc;
@Autowired
private MemoryCacheService myMemoryCacheService;
@Override
@Transactional
public void addTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel, RequestDetails theRequest) {
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theId, theRequest);
if (entity == null) {
throw new ResourceNotFoundException(theId);
}
for (BaseTag next : new ArrayList<>(entity.getTags())) {
if (ObjectUtil.equals(next.getTag().getTagType(), theTagType) &&
ObjectUtil.equals(next.getTag().getSystem(), theScheme) &&
ObjectUtil.equals(next.getTag().getCode(), theTerm)) {
return;
}
}
entity.setHasTags(true);
TagDefinition def = getTagOrNull(TagTypeEnum.TAG, theScheme, theTerm, theLabel);
if (def != null) {
BaseTag newEntity = entity.addTag(def);
if (newEntity.getTagId() == null) {
myEntityManager.persist(newEntity);
myEntityManager.merge(entity);
}
}
ourLog.debug("Processed addTag {}/{} on {} in {}ms", theScheme, theTerm, theId, w.getMillisAndRestart());
}
@Override
public DaoMethodOutcome create(final T theResource) {
return create(theResource, null, true, new TransactionDetails(), null);
@ -700,7 +670,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
if (!hasTag) {
theEntity.setHasTags(true);
TagDefinition def = getTagOrNull(nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
TagDefinition def = getTagOrNull(theTransactionDetails, nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
if (def != null) {
BaseTag newEntity = theEntity.addTag(def);
if (newEntity.getTagId() == null) {

View File

@ -33,6 +33,7 @@ import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
@ -82,23 +83,43 @@ public class HapiTransactionService {
}
}
} catch (ResourceVersionConflictException e) {
ourLog.debug("Version conflict detected: {}", e.toString());
} catch (ResourceVersionConflictException | DataIntegrityViolationException e) {
ourLog.debug("Version conflict detected", e);
if (theOnRollback != null) {
theOnRollback.run();
}
HookParams params = new HookParams()
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
ResourceVersionConflictResolutionStrategy conflictResolutionStrategy = (ResourceVersionConflictResolutionStrategy) JpaInterceptorBroadcaster.doCallHooksAndReturnObject(myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_VERSION_CONFLICT, params);
if (conflictResolutionStrategy != null && conflictResolutionStrategy.isRetry()) {
if (i <= conflictResolutionStrategy.getMaxRetries()) {
continue;
}
int maxRetries = 0;
ourLog.info("Max retries ({}) exceeded for version conflict", conflictResolutionStrategy.getMaxRetries());
/*
* If two client threads both concurrently try to add the same tag that isn't
* known to the system already, they'll both try to create a row in HFJ_TAG_DEF,
* which is the tag definition table. In that case, a constraint error will be
* thrown by one of the client threads, so we auto-retry in order to avoid
* annopying spurious failures for the client.
*/
if (e.getMessage().contains("HFJ_TAG_DEF")) {
maxRetries = 3;
}
if (maxRetries == 0) {
HookParams params = new HookParams()
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
ResourceVersionConflictResolutionStrategy conflictResolutionStrategy = (ResourceVersionConflictResolutionStrategy) JpaInterceptorBroadcaster.doCallHooksAndReturnObject(myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_VERSION_CONFLICT, params);
if (conflictResolutionStrategy != null && conflictResolutionStrategy.isRetry()) {
maxRetries = conflictResolutionStrategy.getMaxRetries();
}
}
if (i < maxRetries) {
sleepAtLeast(250, false);
continue;
}
if (maxRetries > 0) {
ourLog.info("Max retries ({}) exceeded for version conflict", maxRetries);
}
throw e;
@ -118,4 +139,21 @@ public class HapiTransactionService {
}
}
@SuppressWarnings("BusyWait")
public static void sleepAtLeast(long theMillis, boolean theLogProgress) {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() <= start + theMillis) {
try {
long timeSinceStarted = System.currentTimeMillis() - start;
long timeToSleep = Math.max(0, theMillis - timeSinceStarted);
if (theLogProgress) {
ourLog.info("Sleeping for {}ms", timeToSleep);
}
Thread.sleep(timeToSleep);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
ourLog.error("Interrupted", e);
}
}
}
}

View File

@ -22,8 +22,11 @@ package ca.uhn.fhir.jpa.util;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.TranslationQuery;
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
@ -64,6 +67,9 @@ public class MemoryCacheService {
case PERSISTENT_ID:
case RESOURCE_LOOKUP:
case PID_TO_FORCED_ID:
case FORCED_ID_TO_PID:
case MATCH_URL:
case RESOURCE_CONDITIONAL_CREATE_VERSION:
default:
timeoutSeconds = 60;
break;
@ -106,7 +112,7 @@ public class MemoryCacheService {
public enum CacheEnum {
TAG_DEFINITION(Pair.class),
TAG_DEFINITION(TagDefinitionCacheKey.class),
PERSISTENT_ID(String.class),
RESOURCE_LOOKUP(String.class),
FORCED_ID_TO_PID(String.class),
@ -124,4 +130,43 @@ public class MemoryCacheService {
}
public static class TagDefinitionCacheKey {
private final TagTypeEnum myType;
private final String mySystem;
private final String myCode;
private final int myHashCode;
@Override
public boolean equals(Object theO) {
boolean retVal = false;
if (theO instanceof TagDefinitionCacheKey) {
TagDefinitionCacheKey that = (TagDefinitionCacheKey) theO;
retVal = new EqualsBuilder()
.append(myType, that.myType)
.append(mySystem, that.mySystem)
.append(myCode, that.myCode)
.isEquals();
}
return retVal;
}
@Override
public int hashCode() {
return myHashCode;
}
public TagDefinitionCacheKey(TagTypeEnum theType, String theSystem, String theCode) {
myType = theType;
mySystem = theSystem;
myCode = theCode;
myHashCode = new HashCodeBuilder(17, 37)
.append(myType)
.append(mySystem)
.append(myCode)
.toHashCode();
}
}
}

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.util;
* #L%
*/
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import com.google.common.collect.ImmutableSet;
@ -345,17 +346,7 @@ public class TestUtil {
}
public static void sleepAtLeast(long theMillis) {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() <= start + theMillis) {
try {
long timeSinceStarted = System.currentTimeMillis() - start;
long timeToSleep = Math.max(0, theMillis - timeSinceStarted);
ourLog.info("Sleeping for {}ms", timeToSleep);
Thread.sleep(timeToSleep);
} catch (InterruptedException theE) {
ourLog.error("Interrupted", theE);
}
}
HapiTransactionService.sleepAtLeast(theMillis, true);
}
public static InstantType getTimestamp(IBaseResource resource) {

View File

@ -2797,39 +2797,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("http://profile/1", profiles.get(0).getValue());
assertEquals("http://profile/2", profiles.get(1).getValue());
myPatientDao.addTag(patientId, TagTypeEnum.TAG, "http://foo", "Cat", "Kittens", null);
myPatientDao.addTag(patientId, TagTypeEnum.TAG, "http://foo", "Cow", "Calves", null);
retrieved = myPatientDao.read(patientId, mySrd);
published = (TagList) retrieved.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
sort(published);
assertEquals(3, published.size());
assertEquals( "Dog", published.get(0).getTerm());
assertEquals( "Puppies", published.get(0).getLabel());
assertEquals(null, published.get(0).getScheme());
assertEquals( "Cat", published.get(1).getTerm());
assertEquals( "Kittens", published.get(1).getLabel());
assertEquals( "http://foo", published.get(1).getScheme());
assertEquals( "Cow", published.get(2).getTerm());
assertEquals( "Calves", published.get(2).getLabel());
assertEquals( "http://foo", published.get(2).getScheme());
secLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(retrieved);
sortCodings(secLabels);
assertEquals(2, secLabels.size());
assertEquals("seclabel:sys:1", secLabels.get(0).getSystemElement().getValue());
assertEquals("seclabel:code:1", secLabels.get(0).getCodeElement().getValue());
assertEquals("seclabel:dis:1", secLabels.get(0).getDisplayElement().getValue());
assertEquals("seclabel:sys:2", secLabels.get(1).getSystemElement().getValue());
assertEquals("seclabel:code:2", secLabels.get(1).getCodeElement().getValue());
assertEquals("seclabel:dis:2", secLabels.get(1).getDisplayElement().getValue());
profiles = ResourceMetadataKeyEnum.PROFILES.get(retrieved);
profiles = sortIds(profiles);
assertEquals(2, profiles.size());
assertEquals("http://profile/1", profiles.get(0).getValue());
assertEquals("http://profile/2", profiles.get(1).getValue());
}
@Test

View File

@ -67,6 +67,7 @@ import org.hl7.fhir.dstu3.model.OperationDefinition;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Period;
import org.hl7.fhir.dstu3.model.PrimitiveType;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.Quantity.QuantityComparator;
import org.hl7.fhir.dstu3.model.Questionnaire;
@ -173,40 +174,19 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
}
private void sort(ArrayList<Coding> thePublished) {
ArrayList<Coding> tags = new ArrayList<Coding>(thePublished);
Collections.sort(tags, new Comparator<Coding>() {
@Override
public int compare(Coding theO1, Coding theO2) {
int retVal = defaultString(theO1.getSystem()).compareTo(defaultString(theO2.getSystem()));
if (retVal == 0) {
retVal = defaultString(theO1.getCode()).compareTo(defaultString(theO2.getCode()));
}
return retVal;
}
});
ArrayList<Coding> tags = new ArrayList<>(thePublished);
tags.sort(Comparator.comparing((Coding o) -> defaultString(o.getSystem())).thenComparing(o -> defaultString(o.getCode())));
thePublished.clear();
for (Coding next : tags) {
thePublished.add(next);
}
thePublished.addAll(tags);
}
private void sortCodings(List<Coding> theSecLabels) {
Collections.sort(theSecLabels, new Comparator<Coding>() {
@Override
public int compare(Coding theO1, Coding theO2) {
return theO1.getSystemElement().getValue().compareTo(theO2.getSystemElement().getValue());
}
});
theSecLabels.sort(Comparator.comparing(o -> o.getSystemElement().getValue()));
}
private List<UriType> sortIds(List<UriType> theProfiles) {
ArrayList<UriType> retVal = new ArrayList<UriType>(theProfiles);
Collections.sort(retVal, new Comparator<UriType>() {
@Override
public int compare(UriType theO1, UriType theO2) {
return theO1.getValue().compareTo(theO2.getValue());
}
});
retVal.sort(Comparator.comparing(PrimitiveType::getValue));
return retVal;
}
@ -3285,8 +3265,8 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals("http://profile/1", profiles.get(0).getValue());
assertEquals("http://profile/2", profiles.get(1).getValue());
myPatientDao.addTag(patientId, TagTypeEnum.TAG, "http://foo", "Cat", "Kittens", null);
myPatientDao.addTag(patientId, TagTypeEnum.TAG, "http://foo", "Cow", "Calves", null);
myPatientDao.metaAddOperation(patientId, new Meta().addTag( "http://foo", "Cat", "Kittens"), null);
myPatientDao.metaAddOperation(patientId, new Meta().addTag( "http://foo", "Cow", "Calves"), null);
retrieved = myPatientDao.read(patientId, mySrd);
published = (ArrayList<Coding>) retrieved.getMeta().getTag();

View File

@ -1,58 +1,44 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import org.apache.commons.lang3.time.DateUtils;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.jpa.util.MemoryCacheService;
import ca.uhn.fhir.rest.param.TokenParam;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.DecimalType;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.InstantType;
import org.hl7.fhir.r4.model.Meta;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.SampledData;
import org.hl7.fhir.r4.model.SearchParameter;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import static ca.uhn.fhir.rest.api.Constants.PARAM_TAG;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoR4MetaTest extends BaseJpaR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4MetaTest.class);
@Autowired
private MemoryCacheService myMemoryCacheService;
/**
* See #1731
@ -123,4 +109,65 @@ public class FhirResourceDaoR4MetaTest extends BaseJpaR4Test {
assertThat(patient.getMeta().getSecurity(), empty());
}
@Test
public void testAddTagAndSecurityLabelWithSameValues() {
Patient patient1 = new Patient();
patient1.getMeta().addTag().setSystem("http://foo").setCode("bar");
patient1.setActive(true);
IIdType pid1 = myPatientDao.create(patient1).getId();
Patient patient2 = new Patient();
patient2.getMeta().addSecurity().setSystem("http://foo").setCode("bar");
patient2.setActive(true);
IIdType pid2 = myPatientDao.create(patient2).getId();
patient1 = myPatientDao.read(pid1);
assertEquals(1, patient1.getMeta().getTag().size());
assertEquals(0, patient1.getMeta().getSecurity().size());
assertEquals("http://foo", patient1.getMeta().getTagFirstRep().getSystem());
assertEquals("bar", patient1.getMeta().getTagFirstRep().getCode());
patient2 = myPatientDao.read(pid2);
assertEquals(0, patient2.getMeta().getTag().size());
assertEquals(1, patient2.getMeta().getSecurity().size());
assertEquals("http://foo", patient2.getMeta().getSecurityFirstRep().getSystem());
assertEquals("bar", patient2.getMeta().getSecurityFirstRep().getCode());
}
@Test
public void testConcurrentAddTag() throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Runnable task = () -> {
Patient patient = new Patient();
patient.getMeta().addTag().setSystem("http://foo").setCode("bar");
patient.setActive(true);
myPatientDao.create(patient);
};
futures.add(pool.submit(task));
}
// Wait for the tasks to complete, should not throw any exception
for (Future<?> next : futures) {
try {
next.get();
} catch (Exception e) {
ourLog.error("Failure", e);
fail(e.toString());
}
}
runInTransaction(() -> {
ourLog.info("Tag definitions:\n * {}", myTagDefinitionDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
});
assertEquals(10, myPatientDao.search(SearchParameterMap.newSynchronous()).sizeOrThrowNpe());
assertEquals(10, myPatientDao.search(SearchParameterMap.newSynchronous(PARAM_TAG, new TokenParam("http://foo", "bar"))).sizeOrThrowNpe());
}
}

View File

@ -4008,8 +4008,8 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
assertEquals("http://profile/1", profiles.get(0).getValue());
assertEquals("http://profile/2", profiles.get(1).getValue());
myPatientDao.addTag(patientId, TagTypeEnum.TAG, "http://foo", "Cat", "Kittens", null);
myPatientDao.addTag(patientId, TagTypeEnum.TAG, "http://foo", "Cow", "Calves", null);
myPatientDao.metaAddOperation(patientId, new Meta().addTag("http://foo", "Cat", "Kittens"), null);
myPatientDao.metaAddOperation(patientId, new Meta().addTag("http://foo", "Cow", "Calves"), null);
retrieved = myPatientDao.read(patientId, mySrd);
published = (ArrayList<Coding>) retrieved.getMeta().getTag();

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -30,6 +30,11 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<!--test dependencies -->
<dependency>
<groupId>org.springframework.batch</groupId>
@ -43,11 +48,6 @@
<version>${project.version}</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
@ -59,15 +59,6 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -149,13 +149,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test-utilities</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -26,11 +26,6 @@
<artifactId>spring-data-jpa</artifactId>
<version>${spring_data_version}</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
@ -55,13 +50,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test-utilities</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
@ -69,10 +64,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -20,19 +20,30 @@ package ca.uhn.fhir.jpa.model.entity;
* #L%
*/
import ca.uhn.fhir.model.api.Tag;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.*;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import java.io.Serializable;
import java.util.Collection;
@Entity
@Table(name = "HFJ_TAG_DEF", uniqueConstraints = {
@UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODE", columnNames = { "TAG_TYPE", "TAG_SYSTEM", "TAG_CODE" })
@UniqueConstraint(name = "IDX_TAGDEF_TYPESYSCODE", columnNames = {"TAG_TYPE", "TAG_SYSTEM", "TAG_CODE"})
})
public class TagDefinition implements Serializable {
@ -45,7 +56,7 @@ public class TagDefinition implements Serializable {
private String myDisplay;
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_TAGDEF_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_TAGDEF_ID")
@SequenceGenerator(name = "SEQ_TAGDEF_ID", sequenceName = "SEQ_TAGDEF_ID")
@Column(name = "TAG_ID")
private Long myId;
@ -59,7 +70,7 @@ public class TagDefinition implements Serializable {
@Column(name = "TAG_SYSTEM", length = 200)
private String mySystem;
@Column(name="TAG_TYPE", nullable=false)
@Column(name = "TAG_TYPE", nullable = false)
@Enumerated(EnumType.ORDINAL)
private TagTypeEnum myTagType;
@ -80,36 +91,40 @@ public class TagDefinition implements Serializable {
return myCode;
}
public String getDisplay() {
return myDisplay;
}
public Long getId() {
return myId;
}
public String getSystem() {
return mySystem;
}
public TagTypeEnum getTagType() {
return myTagType;
}
public void setCode(String theCode) {
myCode = theCode;
myHashCode = null;
}
public String getDisplay() {
return myDisplay;
}
public void setDisplay(String theDisplay) {
myDisplay = theDisplay;
}
public Long getId() {
return myId;
}
public void setId(Long theId) {
myId = theId;
}
public String getSystem() {
return mySystem;
}
public void setSystem(String theSystem) {
mySystem = theSystem;
myHashCode = null;
}
public TagTypeEnum getTagType() {
return myTagType;
}
public void setTagType(TagTypeEnum theTagType) {
myTagType = theTagType;
myHashCode = null;
@ -137,7 +152,7 @@ public class TagDefinition implements Serializable {
return b.isEquals();
}
@Override
public int hashCode() {
if (myHashCode == null) {
@ -159,7 +174,4 @@ public class TagDefinition implements Serializable {
retVal.append("display", myDisplay);
return retVal.build();
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -78,11 +78,6 @@
<!-- test dependencies -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
@ -93,11 +88,6 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -25,11 +25,6 @@
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -169,7 +169,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-converter</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
</dependencies>

View File

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

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -184,7 +184,15 @@ public class OpenApiInterceptor {
if (isBlank(requestPath) || requestPath.equals("/")) {
Set<String> highestRankedAcceptValues = RestfulServerUtils.parseAcceptHeaderAndReturnHighestRankedOptions(theRequest);
if (highestRankedAcceptValues.contains(Constants.CT_HTML)) {
theResponse.sendRedirect("./swagger-ui/");
String serverBase = ".";
if (theRequestDetails.getServletRequest() != null) {
IServerAddressStrategy addressStrategy = theRequestDetails.getServer().getServerAddressStrategy();
serverBase = addressStrategy.determineServerBase(theRequest.getServletContext(), theRequest);
}
String redirectUrl = theResponse.encodeRedirectURL(serverBase + "/swagger-ui/");
theResponse.sendRedirect(redirectUrl);
theResponse.getWriter().close();
return false;
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -200,12 +200,6 @@
<artifactId>spring-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -260,11 +260,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -58,75 +58,47 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r5</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
</exclusions>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<dependency>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-chain</artifactId>
<groupId>commons-chain</groupId>
</exclusion>
<exclusion>
<artifactId>commons-validator</artifactId>
<groupId>commons-validator</groupId>
</exclusion>
<exclusion>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.tinder;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -39,7 +38,6 @@ public class ExamineTestTrace {
ourLog.info("Started {}", started.size());
ourLog.info("Finished {}", finished.size());
ourLog.info(CollectionUtils.disjunction(started, finished).toString());
}

View File

@ -22,7 +22,6 @@ import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.EscapeTool;
import ca.uhn.fhir.tinder.AbstractGenerator.ExecutionException;
import ca.uhn.fhir.tinder.AbstractGenerator.FailureException;
@ -360,7 +359,7 @@ public class TinderGenericSingleFileMojo extends AbstractMojo {
ctx.put("version", version);
ctx.put("isRi", BaseStructureParser.determineVersionEnum(version).isRi());
ctx.put("hash", "#");
ctx.put("esc", new EscapeTool());
ctx.put("esc", new TinderResourceGeneratorMojo.EscapeTool());
if (BaseStructureParser.determineVersionEnum(version).isRi()) {
ctx.put("resourcePackage", "org.hl7.fhir." + version + ".model");
} else {

View File

@ -11,7 +11,6 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.project.MavenProject;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.EscapeTool;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
@ -146,7 +145,7 @@ public class TinderJpaRestServerMojo extends AbstractMojo {
ctx.put("configPackageBase", configPackageBase);
ctx.put("version", version);
ctx.put("package_suffix", packageSuffix);
ctx.put("esc", new EscapeTool());
ctx.put("esc", new TinderResourceGeneratorMojo.EscapeTool());
if (BaseStructureSpreadsheetParser.determineVersionEnum(version).isRi()) {
ctx.put("resourcePackage", "org.hl7.fhir." + version + ".model");
} else {

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.tinder;
import ca.uhn.fhir.tinder.parser.ResourceGeneratorUsingModel;
import ca.uhn.fhir.tinder.parser.ResourceGeneratorUsingSpreadsheet;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
@ -10,7 +11,6 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.EscapeTool;
import java.io.*;
@ -72,4 +72,13 @@ public class TinderResourceGeneratorMojo extends AbstractGeneratorMojo {
public File getTargetDirectory() {
return targetDirectory;
}
public static class EscapeTool {
public String html(String theHtml) {
return StringEscapeUtils.escapeHtml4(theHtml);
}
}
}

View File

@ -17,7 +17,6 @@ import org.apache.commons.lang3.text.WordUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.EscapeTool;
import java.io.*;
import java.nio.charset.Charset;
@ -287,7 +286,7 @@ public class ValueSetGenerator {
InputStream templateIs = null;
ctx.put("valueSet", theValueSetTm);
ctx.put("packageBase", thePackageBase);
ctx.put("esc", new EscapeTool());
ctx.put("esc", new TinderResourceGeneratorMojo.EscapeTool());
VelocityEngine v = VelocityHelper.configureVelocityEngine(myTemplateFile, myVelocityPath, myVelocityProperties);
if (myTemplateFile != null) {

View File

@ -29,13 +29,13 @@ import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import ca.uhn.fhir.tinder.TinderResourceGeneratorMojo;
import org.apache.commons.lang.WordUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.EscapeTool;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.tinder.AbstractGenerator;
@ -423,7 +423,7 @@ public class TinderGeneratorTask extends Task {
ctx.put("version", version);
ctx.put("isRi", BaseStructureSpreadsheetParser.determineVersionEnum(version).isRi());
ctx.put("hash", "#");
ctx.put("esc", new EscapeTool());
ctx.put("esc", new TinderResourceGeneratorMojo.EscapeTool());
if (BaseStructureSpreadsheetParser.determineVersionEnum(version).isRi()) {
ctx.put("resourcePackage", "org.hl7.fhir." + version + ".model");
} else {

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Binary;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.tinder.TinderResourceGeneratorMojo;
import ca.uhn.fhir.tinder.TinderStructuresMojo;
import ca.uhn.fhir.tinder.ValueSetGenerator;
import ca.uhn.fhir.tinder.VelocityHelper;
@ -22,7 +23,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.EscapeTool;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@ -519,7 +519,7 @@ public abstract class BaseStructureParser {
ctx.put("searchParamsReference", (theResource.getSearchParametersResource()));
ctx.put("searchParamsWithoutComposite", (theResource.getSearchParametersWithoutComposite()));
ctx.put("includes", (theResource.getIncludes()));
ctx.put("esc", new EscapeTool());
ctx.put("esc", new TinderResourceGeneratorMojo.EscapeTool());
ctx.put("isRi", determineVersionEnum().isRi());
String capitalize = WordUtils.capitalize(myVersion);
@ -664,7 +664,7 @@ public abstract class BaseStructureParser {
ctx.put("nameToDatatypeClass", myNameToDatatypeClass);
ctx.put("version", myVersion.replace(".", ""));
ctx.put("versionEnumName", determineVersionEnum().name());
ctx.put("esc", new EscapeTool());
ctx.put("esc", new TinderResourceGeneratorMojo.EscapeTool());
ctx.put("isRi", determineVersionEnum().isRi());
ctx.put("package_suffix", packageSuffix);
String capitalize = WordUtils.capitalize(myVersion);

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

21
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<description>An open-source implementation of the FHIR specification in Java.</description>
<url>https://hapifhir.io</url>
@ -978,6 +978,11 @@
<artifactId>flexmark-profile-pegdown</artifactId>
<version>${flexmark_version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
@ -993,6 +998,11 @@
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
@ -1321,13 +1331,8 @@
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE9-SNAPSHOT</version>
<version>5.4.0-PRE10-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

3287
tmp2.txt

File diff suppressed because it is too large Load Diff