diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java index dc55bd682e6..0884df8e653 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java @@ -181,7 +181,7 @@ public enum FhirVersionEnum { private String myVersion; - public Dstu3Version() { + Dstu3Version() { try { Class c = Class.forName("org.hl7.fhir.dstu3.model.Constants"); myVersion = (String) c.getDeclaredField("VERSION").get(null); @@ -201,7 +201,7 @@ public enum FhirVersionEnum { private String myVersion; - public R4Version() { + R4Version() { try { Class c = Class.forName("org.hl7.fhir.r4.model.Constants"); myVersion = (String) c.getDeclaredField("VERSION").get(null); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParserErrorHandler.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParserErrorHandler.java index 485311e5736..f7562c95b92 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParserErrorHandler.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParserErrorHandler.java @@ -55,7 +55,7 @@ public interface IParserErrorHandler { void incorrectJsonType(IParseLocation theLocation, String theElementName, ValueType theExpectedValueType, ScalarType theExpectedScalarType, ValueType theFoundValueType, ScalarType theFoundScalarType); /** - * The parser detected an atttribute value that was invalid (such as: empty "" values are not permitted) + * The parser detected an attribute value that was invalid (such as: empty "" values are not permitted) * * @param theLocation * The location in the document. Note that this may be null as the ParseLocation feature is experimental. Use with caution, as the API may change. @@ -70,7 +70,7 @@ public interface IParserErrorHandler { * * @param theLocation * The location in the document. Note that this may be null as the ParseLocation feature is experimental. Use with caution, as the API may change. - * @param theReference The actual invalid reference (e.g. "#3") + * @param theElementName The missing element name * @since 2.1 */ void missingRequiredElement(IParseLocation theLocation, String theElementName); @@ -123,7 +123,7 @@ public interface IParserErrorHandler { * type which will currently always be set to null. This interface is included here so that * locations can be added to the API in a future release without changing the API. */ - public interface IParseLocation { + interface IParseLocation { /** * Returns the name of the parent element (the element containing the element currently being parsed) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index b8fff2e30d4..d56aff6e5d2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -1033,7 +1033,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { } else { parentElementName = "extension"; } - getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url"); + getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName(parentElementName), "url"); url = null; } else { url = getExtensionUrl(jsonElement.getAsString()); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParseLocation.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParseLocation.java index 8df9a37aa96..2c0dc4eec4f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParseLocation.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParseLocation.java @@ -29,9 +29,8 @@ class ParseLocation implements IParseLocation { /** * Constructor */ - public ParseLocation(String theParentElementName) { + public ParseLocation() { super(); - myParentElementName = theParentElementName; } @Override @@ -39,4 +38,9 @@ class ParseLocation implements IParseLocation { return myParentElementName; } + public ParseLocation setParentElementName(String theParentElementName) { + myParentElementName = theParentElementName; + return this; + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index b4c6d6db00f..6f4c5d02ad6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -806,7 +806,7 @@ class ParserState { @SuppressWarnings("unchecked") List securityLabels = (List) myMap.get(ResourceMetadataKeyEnum.SECURITY_LABELS); if (securityLabels == null) { - securityLabels = new ArrayList(); + securityLabels = new ArrayList<>(); myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels); } IBase securityLabel = myContext.getVersion().newCodingDt(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index ea266d7a13a..c1fcfa07577 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -139,7 +139,7 @@ public class XmlParser extends BaseParser /* implements IParser */ { Attribute urlAttr = elem.getAttributeByName(new QName("url")); String url; if (urlAttr == null || isBlank(urlAttr.getValue())) { - getErrorHandler().missingRequiredElement(new ParseLocation("extension"), "url"); + getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("extension"), "url"); url = null; } else { url = urlAttr.getValue(); @@ -149,7 +149,7 @@ public class XmlParser extends BaseParser /* implements IParser */ { Attribute urlAttr = elem.getAttributeByName(new QName("url")); String url; if (urlAttr == null || isBlank(urlAttr.getValue())) { - getErrorHandler().missingRequiredElement(new ParseLocation("modifierExtension"), "url"); + getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("modifierExtension"), "url"); url = null; } else { url = urlAttr.getValue(); diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java b/hapi-fhir-cli/hapi-fhir-cli-app/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java index 5025b098918..f57946927a1 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java +++ b/hapi-fhir-cli/hapi-fhir-cli-app/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.StructureDefinition; import ca.uhn.fhir.model.dstu2.resource.ValueSet; import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; @@ -163,7 +164,7 @@ public class ValidationDataUploader extends BaseCommand { ValueSet next = (ValueSet) i.getResource(); next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; @@ -182,7 +183,7 @@ public class ValidationDataUploader extends BaseCommand { ValueSet next = (ValueSet) i.getResource(); next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; @@ -200,7 +201,7 @@ public class ValidationDataUploader extends BaseCommand { ValueSet next = (ValueSet) i.getResource(); next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; } @@ -225,7 +226,7 @@ public class ValidationDataUploader extends BaseCommand { } next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading StructureDefinition {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading StructureDefinition {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); try { client.update().resource(next).execute(); } catch (Exception e) { @@ -268,12 +269,14 @@ public class ValidationDataUploader extends BaseCommand { int bytes = ctx.newXmlParser().encodeResourceToString(next).length(); - ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[]{count, total, next.getIdElement().getValue(), bytes}); + ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[] {count, total, next.getIdElement().getValue(), bytes}); try { IIdType id = client.update().resource(next).execute().getId(); ourLog.info(" - Got ID: {}", id.getValue()); } catch (UnprocessableEntityException e) { ourLog.warn("UnprocessableEntityException: " + e.toString()); + } catch (BaseServerResponseException e) { + ourLog.warn("Server responded HTTP " + e.getStatusCode() + ": " + e.toString()); } count++; } @@ -293,7 +296,7 @@ public class ValidationDataUploader extends BaseCommand { org.hl7.fhir.dstu3.model.Resource next = i.getResource(); next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); try { client.update().resource(next).execute(); } catch (Exception e) { @@ -318,7 +321,7 @@ public class ValidationDataUploader extends BaseCommand { } next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; } @@ -364,7 +367,7 @@ public class ValidationDataUploader extends BaseCommand { int bytes = theCtx.newXmlParser().encodeResourceToString(next).length(); - ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[]{count, total, next.getIdElement().getValue(), bytes}); + ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[] {count, total, next.getIdElement().getValue(), bytes}); try { IIdType id = client.update().resource(next).execute().getId(); ourLog.info(" - Got ID: {}", id.getValue()); @@ -388,7 +391,7 @@ public class ValidationDataUploader extends BaseCommand { org.hl7.fhir.r4.model.Resource next = i.getResource(); next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; @@ -410,7 +413,7 @@ public class ValidationDataUploader extends BaseCommand { } next.setId(next.getIdElement().toUnqualifiedVersionless()); - ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; } @@ -470,7 +473,7 @@ public class ValidationDataUploader extends BaseCommand { continue; } - ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[]{name, count, total, next.getIdElement().getValue()}); + ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[] {name, count, total, next.getIdElement().getValue()}); client.update().resource(next).execute(); count++; @@ -518,8 +521,12 @@ public class ValidationDataUploader extends BaseCommand { continue; } - ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[]{name, count, total, next.getIdElement().getValue()}); - client.update().resource(next).execute(); + ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[] {name, count, total, next.getIdElement().getValue()}); + try { + client.update().resource(next).execute(); + } catch (BaseServerResponseException e) { + ourLog.warn("Server responded HTTP " + e.getStatusCode() + ": " + e.toString()); + } count++; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index 3a0fbe4b642..bb3ce1e6ec1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -82,10 +82,11 @@ import java.util.Map.Entry; import static org.apache.commons.lang3.StringUtils.*; +@SuppressWarnings("WeakerAccess") public abstract class BaseHapiFhirDao implements IDao { - public static final long INDEX_STATUS_INDEXED = Long.valueOf(1L); - public static final long INDEX_STATUS_INDEXING_FAILED = Long.valueOf(2L); + public static final long INDEX_STATUS_INDEXED = 1L; + public static final long INDEX_STATUS_INDEXING_FAILED = 2L; public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile"; public static final String OO_SEVERITY_ERROR = "error"; public static final String OO_SEVERITY_INFO = "information"; @@ -379,7 +380,7 @@ public abstract class BaseHapiFhirDao implements IDao { } else { ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime); if (theLinks.add(resourceLink)) { - ourLog.info("Indexing remote resource reference URL: {}", nextId); + ourLog.debug("Indexing remote resource reference URL: {}", nextId); } continue; } @@ -417,7 +418,7 @@ public abstract class BaseHapiFhirDao implements IDao { IBaseResource newResource = missingResourceDef.newInstance(); newResource.setId(resName + "/" + id); IFhirResourceDao placeholderResourceDao = (IFhirResourceDao) getDao(newResource.getClass()); - ourLog.info("Automatically creating empty placeholder resource: {}", newResource.getIdElement().getValue()); + ourLog.debug("Automatically creating empty placeholder resource: {}", newResource.getIdElement().getValue()); valueOf = placeholderResourceDao.update(newResource).getEntity().getId(); } else { throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit); @@ -673,7 +674,7 @@ public abstract class BaseHapiFhirDao implements IDao { @SuppressWarnings("unchecked") public IFhirResourceDao getDao(Class theType) { if (myResourceTypeToDao == null) { - Map, IFhirResourceDao> theResourceTypeToDao = new HashMap, IFhirResourceDao>(); + Map, IFhirResourceDao> theResourceTypeToDao = new HashMap<>(); for (IFhirResourceDao next : myResourceDaos) { theResourceTypeToDao.put(next.getResourceType(), next); } @@ -1549,7 +1550,7 @@ public abstract class BaseHapiFhirDao implements IDao { } Long next = matches.iterator().next(); String newId = translatePidIdToForcedId(resourceTypeString, next); - ourLog.info("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId); + ourLog.debug("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId); nextRef.setReference(newId); } } @@ -1615,7 +1616,7 @@ public abstract class BaseHapiFhirDao implements IDao { } if (!changed.isChanged() && !theForceUpdate && myConfig.isSuppressUpdatesWithNoChange()) { - ourLog.info("Resource {} has not changed", theEntity.getIdDt().toUnqualified().getValue()); + ourLog.debug("Resource {} has not changed", theEntity.getIdDt().toUnqualified().getValue()); if (theResource != null) { populateResourceIdFromEntity(theEntity, theResource); } @@ -1657,7 +1658,7 @@ public abstract class BaseHapiFhirDao implements IDao { historyEntry.setEncoding(changed.getEncoding()); historyEntry.setResource(changed.getResource()); - ourLog.info("Saving history entry {}", historyEntry.getIdDt()); + ourLog.debug("Saving history entry {}", historyEntry.getIdDt()); myResourceHistoryTableDao.save(historyEntry); } @@ -1765,7 +1766,7 @@ public abstract class BaseHapiFhirDao implements IDao { // Store composite string uniques if (getConfig().isUniqueIndexesEnabled()) { for (ResourceIndexedCompositeStringUnique next : removeCommon(existingCompositeStringUniques, compositeStringUniques)) { - ourLog.info("Removing unique index: {}", next); + ourLog.debug("Removing unique index: {}", next); myEntityManager.remove(next); theEntity.getParamsCompositeStringUnique().remove(next); } @@ -1776,7 +1777,7 @@ public abstract class BaseHapiFhirDao implements IDao { throw new PreconditionFailedException("Can not create resource of type " + theEntity.getResourceType() + " as it would create a duplicate index matching query: " + next.getIndexString() + " (existing index belongs to " + existing.getResource().getIdDt().toUnqualifiedVersionless().getValue() + ")"); } } - ourLog.info("Persisting unique index: {}", next); + ourLog.debug("Persisting unique index: {}", next); myEntityManager.persist(next); } } @@ -1821,7 +1822,7 @@ public abstract class BaseHapiFhirDao implements IDao { if (nextChildDef instanceof RuntimeChildResourceDefinition) { RuntimeChildResourceDefinition nextChildDefRes = (RuntimeChildResourceDefinition) nextChildDef; - Set validTypes = new HashSet(); + Set validTypes = new HashSet<>(); boolean allowAny = false; for (Class nextValidType : nextChildDefRes.getResourceTypes()) { if (nextValidType.isInterface()) { @@ -2147,7 +2148,7 @@ public abstract class BaseHapiFhirDao implements IDao { } if (forcedId.isEmpty() == false) { - List retVal = new ArrayList(forcedId.size()); + List retVal = new ArrayList<>(forcedId.size()); for (ForcedId next : forcedId) { retVal.add(next.getResourcePid()); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 9c26432e15c..4aa6732ec02 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -127,7 +127,7 @@ public abstract class BaseHapiFhirResourceDao extends B } } - ourLog.info("Processed addTag {}/{} on {} in {}ms", theScheme, theTerm, theId, w.getMillisAndRestart()); + ourLog.debug("Processed addTag {}/{} on {} in {}ms", theScheme, theTerm, theId, w.getMillisAndRestart()); } @Override @@ -273,7 +273,7 @@ public abstract class BaseHapiFhirResourceDao extends B validateDeleteConflictsEmptyOrThrowException(deleteConflicts); - ourLog.info("Processed delete on {} in {}ms", theId.getValue(), w.getMillisAndRestart()); + ourLog.debug("Processed delete on {} in {}ms", theId.getValue(), w.getMillisAndRestart()); return retVal; } @@ -350,7 +350,7 @@ public abstract class BaseHapiFhirResourceDao extends B OperationOutcomeUtil.addIssue(getContext(), oo, severity, message, null, code); } - ourLog.info("Processed delete on {} (matched {} resource(s)) in {}ms", theUrl, deletedResources.size(), w.getMillis()); + ourLog.debug("Processed delete on {} (matched {} resource(s)) in {}ms", theUrl, deletedResources.size(), w.getMillis()); DeleteMethodOutcome retVal = new DeleteMethodOutcome(); retVal.setDeletedEntities(deletedResources); @@ -462,7 +462,7 @@ public abstract class BaseHapiFhirResourceDao extends B String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulCreate", outcome.getId(), w.getMillisAndRestart()); outcome.setOperationOutcome(createInfoOperationOutcome(msg)); - ourLog.info(msg); + ourLog.debug(msg); return outcome; } @@ -530,7 +530,7 @@ public abstract class BaseHapiFhirResourceDao extends B StopWatch w = new StopWatch(); TagList tags = super.getTags(myResourceType, null); - ourLog.info("Processed getTags on {} in {}ms", myResourceName, w.getMillisAndRestart()); + ourLog.debug("Processed getTags on {} in {}ms", myResourceName, w.getMillisAndRestart()); return tags; } @@ -557,7 +557,7 @@ public abstract class BaseHapiFhirResourceDao extends B StopWatch w = new StopWatch(); TagList retVal = super.getTags(myResourceType, theResourceId); - ourLog.info("Processed getTags on {} in {}ms", theResourceId, w.getMillisAndRestart()); + ourLog.debug("Processed getTags on {} in {}ms", theResourceId, w.getMillisAndRestart()); return retVal; } @@ -569,7 +569,7 @@ public abstract class BaseHapiFhirResourceDao extends B StopWatch w = new StopWatch(); IBundleProvider retVal = super.history(myResourceName, null, theSince, theUntil); - ourLog.info("Processed history on {} in {}ms", myResourceName, w.getMillisAndRestart()); + ourLog.debug("Processed history on {} in {}ms", myResourceName, w.getMillisAndRestart()); return retVal; } @@ -586,7 +586,7 @@ public abstract class BaseHapiFhirResourceDao extends B IBundleProvider retVal = super.history(myResourceName, entity.getId(), theSince, theUntil); - ourLog.info("Processed history on {} in {}ms", id, w.getMillisAndRestart()); + ourLog.debug("Processed history on {} in {}ms", id, w.getMillisAndRestart()); return retVal; } @@ -622,7 +622,7 @@ public abstract class BaseHapiFhirResourceDao extends B if (myDaoConfig.isMarkResourcesForReindexingUponSearchParameterChange()) { if (isNotBlank(theExpression)) { final String resourceType = theExpression.substring(0, theExpression.indexOf('.')); - ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, theExpression); + ourLog.debug("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, theExpression); TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); @@ -633,7 +633,7 @@ public abstract class BaseHapiFhirResourceDao extends B } }); - ourLog.info("Marked {} resources for reindexing", updatedCount); + ourLog.debug("Marked {} resources for reindexing", updatedCount); } } @@ -665,7 +665,7 @@ public abstract class BaseHapiFhirResourceDao extends B doMetaAdd(theMetaAdd, history); } - ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[]{theResourceId, w.getMillisAndRestart()}); + ourLog.debug("Processed metaAddOperation on {} in {}ms", new Object[]{theResourceId, w.getMillisAndRestart()}); @SuppressWarnings("unchecked") MT retVal = (MT) metaGetOperation(theMetaAdd.getClass(), theResourceId, theRequestDetails); @@ -699,7 +699,7 @@ public abstract class BaseHapiFhirResourceDao extends B myEntityManager.flush(); - ourLog.info("Processed metaDeleteOperation on {} in {}ms", new Object[]{theResourceId.getValue(), w.getMillisAndRestart()}); + ourLog.debug("Processed metaDeleteOperation on {} in {}ms", new Object[]{theResourceId.getValue(), w.getMillisAndRestart()}); @SuppressWarnings("unchecked") MT retVal = (MT) metaGetOperation(theMetaDel.getClass(), theResourceId, theRequestDetails); @@ -864,7 +864,7 @@ public abstract class BaseHapiFhirResourceDao extends B throw new ResourceGoneException("Resource was deleted at " + deleted.getValueAsString()); } - ourLog.info("Processed read on {} in {}ms", theId.getValue(), w.getMillisAndRestart()); + ourLog.debug("Processed read on {} in {}ms", theId.getValue(), w.getMillisAndRestart()); return retVal; } @@ -968,7 +968,7 @@ public abstract class BaseHapiFhirResourceDao extends B myEntityManager.merge(entity); - ourLog.info("Processed remove tag {}/{} on {} in {}ms", theScheme, theTerm, theId.getValue(), w.getMillisAndRestart()); + ourLog.debug("Processed remove tag {}/{} on {} in {}ms", theScheme, theTerm, theId.getValue(), w.getMillisAndRestart()); } @Transactional(propagation = Propagation.SUPPORTS) @@ -1282,7 +1282,7 @@ public abstract class BaseHapiFhirResourceDao extends B String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulCreate", outcome.getId(), w.getMillisAndRestart()); outcome.setOperationOutcome(createInfoOperationOutcome(msg)); - ourLog.info(msg); + ourLog.debug(msg); return outcome; } @@ -1339,7 +1339,7 @@ public abstract class BaseHapiFhirResourceDao extends B } if (myDaoConfig.isEnforceReferentialIntegrityOnDelete() == false && !theForValidate) { - ourLog.info("Deleting {} resource dependencies which can no longer be satisfied", resultList.size()); + ourLog.debug("Deleting {} resource dependencies which can no longer be satisfied", resultList.size()); myResourceLinkDao.delete(resultList); return; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index a2dab374bbc..816dfb55328 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -83,7 +83,7 @@ public class SearchBuilder implements ISearchBuilder { private static final List EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList()); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilder.class); - private static Long NO_MORE = Long.valueOf(-1); + private static Long NO_MORE = -1L; private static HandlerTypeEnum ourLastHandlerMechanismForUnitTest; private List myAlsoIncludePids; private CriteriaBuilder myBuilder; @@ -331,10 +331,9 @@ public class SearchBuilder implements ISearchBuilder { List codePredicates = new ArrayList(); for (IQueryParameterType nextOr : theList) { - IQueryParameterType params = nextOr; - if (params instanceof ReferenceParam) { - ReferenceParam ref = (ReferenceParam) params; + if (nextOr instanceof ReferenceParam) { + ReferenceParam ref = (ReferenceParam) nextOr; if (isBlank(ref.getChain())) { IIdType dt = new IdDt(ref.getBaseUrl(), ref.getResourceType(), ref.getIdPart(), null); @@ -471,7 +470,7 @@ public class SearchBuilder implements ISearchBuilder { IQueryParameterType chainValue; if (remainingChain != null) { if (param == null || param.getParamType() != RestSearchParameterTypeEnum.REFERENCE) { - ourLog.debug("Type {} parameter {} is not a reference, can not chain {}", new Object[]{nextType.getSimpleName(), chain, remainingChain}); + ourLog.debug("Type {} parameter {} is not a reference, can not chain {}", new Object[] {nextType.getSimpleName(), chain, remainingChain}); continue; } @@ -533,7 +532,7 @@ public class SearchBuilder implements ISearchBuilder { } } else { - throw new IllegalArgumentException("Invalid token type (expecting ReferenceParam): " + params.getClass()); + throw new IllegalArgumentException("Invalid token type (expecting ReferenceParam): " + nextOr.getClass()); } } @@ -1475,37 +1474,37 @@ public class SearchBuilder implements ISearchBuilder { switch (param.getParamType()) { case STRING: joinAttrName = "myParamsString"; - sortAttrName = new String[]{"myValueExact"}; + sortAttrName = new String[] {"myValueExact"}; joinType = JoinEnum.STRING; break; case DATE: joinAttrName = "myParamsDate"; - sortAttrName = new String[]{"myValueLow"}; + sortAttrName = new String[] {"myValueLow"}; joinType = JoinEnum.DATE; break; case REFERENCE: joinAttrName = "myResourceLinks"; - sortAttrName = new String[]{"myTargetResourcePid"}; + sortAttrName = new String[] {"myTargetResourcePid"}; joinType = JoinEnum.REFERENCE; break; case TOKEN: joinAttrName = "myParamsToken"; - sortAttrName = new String[]{"mySystem", "myValue"}; + sortAttrName = new String[] {"mySystem", "myValue"}; joinType = JoinEnum.TOKEN; break; case NUMBER: joinAttrName = "myParamsNumber"; - sortAttrName = new String[]{"myValue"}; + sortAttrName = new String[] {"myValue"}; joinType = JoinEnum.NUMBER; break; case URI: joinAttrName = "myParamsUri"; - sortAttrName = new String[]{"myUri"}; + sortAttrName = new String[] {"myUri"}; joinType = JoinEnum.URI; break; case QUANTITY: joinAttrName = "myParamsQuantity"; - sortAttrName = new String[]{"myValue"}; + sortAttrName = new String[] {"myValue"}; joinType = JoinEnum.QUANTITY; break; default: @@ -1780,7 +1779,7 @@ public class SearchBuilder implements ISearchBuilder { nextRoundMatches = pidsToInclude; } while (includes.size() > 0 && nextRoundMatches.size() > 0 && addedSomeThisRound); - ourLog.info("Loaded {} {} in {} rounds and {} ms", new Object[]{allAdded.size(), theReverseMode ? "_revincludes" : "_includes", roundCounts, w.getMillisAndRestart()}); + ourLog.info("Loaded {} {} in {} rounds and {} ms", new Object[] {allAdded.size(), theReverseMode ? "_revincludes" : "_includes", roundCounts, w.getMillisAndRestart()}); return allAdded; } @@ -2006,8 +2005,17 @@ public class SearchBuilder implements ISearchBuilder { RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(theResourceType); RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName); List path = param.getPathsSplit(); - Predicate type = theFrom.get("mySourcePath").in(path); - return type; + + /* + * SearchParameters can declare paths on multiple resources + * types. Here we only want the ones that actually apply. + */ + for (Iterator iter = path.iterator(); iter.hasNext(); ) { + if (!iter.next().startsWith(theResourceType + ".")) { + iter.remove(); + } + } + return theFrom.get("mySourcePath").in(path); } private static List filterResourceIdsByLastUpdated(EntityManager theEntityManager, final DateRangeParam theLastUpdated, Collection thePids) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3.java index 5c8be60331e..7513d25ea8f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/SearchParamExtractorDstu3.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.dstu3; */ import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.trim; import java.math.BigDecimal; import java.util.*; @@ -478,8 +479,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen multiType = true; } - List systems = new ArrayList(); - List codes = new ArrayList(); + List systems = new ArrayList<>(); + List codes = new ArrayList<>(); // String needContactPointSystem = null; // if (nextPath.contains(".where(system='phone')")) { @@ -693,11 +694,11 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen IWorkerContext worker = new org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport); FHIRPathEngine fp = new FHIRPathEngine(worker); - List values = new ArrayList(); + List values = new ArrayList<>(); try { String[] nextPathsSplit = SPLIT.split(thePaths); for (String nextPath : nextPathsSplit) { - List allValues = fp.evaluate((Base) theResource, nextPath); + List allValues = fp.evaluate((Base) theResource, trim(nextPath)); if (allValues.isEmpty() == false) { values.addAll(allValues); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSearchParameterR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSearchParameterR4.java index 2baba40c03f..91861ac567b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSearchParameterR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSearchParameterR4.java @@ -40,9 +40,6 @@ import static org.apache.commons.lang3.StringUtils.isBlank; public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4 implements IFhirResourceDaoSearchParameter { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSearchParameterR4.class); - - @Autowired private IFhirSystemDao mySystemDao; @@ -130,7 +127,6 @@ public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4 results = toUnqualifiedVersionlessIdValues(myMedicationRequestDao.search(map)); + assertThat(results, contains(mrId)); + } + + /** + * See #863 + */ + @Test + public void testParamWithMultipleBasesToken() { + SearchParameter sp = new SearchParameter(); + sp.setUrl("http://clinicalcloud.solutions/fhir/SearchParameter/request-reason"); + sp.setName("reason"); + sp.setStatus(Enumerations.PublicationStatus.ACTIVE); + sp.setCode("reason"); + sp.addBase("MedicationRequest"); + sp.addBase("ProcedureRequest"); + sp.setType(Enumerations.SearchParamType.TOKEN); + sp.setExpression("MedicationRequest.reasonCode | ProcedureRequest.reasonCode"); + mySearchParameterDao.create(sp); + mySearchParamRegsitry.forceRefresh(); + + MedicationRequest mr = new MedicationRequest(); + mr.addReasonCode().addCoding().setSystem("foo").setCode("bar"); + String mrId = myMedicationRequestDao.create(mr).getId().toUnqualifiedVersionless().getValue(); + + ProcedureRequest pr = new ProcedureRequest(); + pr.addReasonCode().addCoding().setSystem("foo").setCode("bar"); + myProcedureRequestDao.create(pr); + + SearchParameterMap map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add("reason", new TokenParam("foo", "bar")); + List results = toUnqualifiedVersionlessIdValues(myMedicationRequestDao.search(map)); + assertThat(results, contains(mrId)); + } + @Test public void testSearchForExtensionReferenceWithNonMatchingTarget() { SearchParameter siblingSp = new SearchParameter(); @@ -271,7 +342,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu assertThat(foundResources, empty()); } - + @Test public void testSearchForExtensionReferenceWithTarget() { SearchParameter siblingSp = new SearchParameter(); @@ -414,7 +485,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu assertThat(foundResources, contains(p1id.getValue())); } - + @Test public void testSearchForExtensionTwoDeepCodeableConcept() { SearchParameter siblingSp = new SearchParameter(); @@ -436,9 +507,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .addExtension() .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new CodeableConcept().addCoding(new Coding().setSystem("foo").setCode("bar"))); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new CodeableConcept().addCoding(new Coding().setSystem("foo").setCode("bar"))); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -474,9 +545,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .addExtension() .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new Coding().setSystem("foo").setCode("bar")); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new Coding().setSystem("foo").setCode("bar")); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -516,9 +587,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new DateType("2012-01-02")); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new DateType("2012-01-02")); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -553,16 +624,16 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .addExtension() .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new DecimalType("2.1")); - + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new DecimalType("2.1")); + IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); SearchParameterMap map; IBundleProvider results; List foundResources; - + map = new SearchParameterMap(); map.add("foobar", new NumberParam("2.1")); results = myPatientDao.search(map); @@ -590,9 +661,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .addExtension() .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new IntegerType(5)); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new IntegerType(5)); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -633,9 +704,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new Reference(aptId.getValue())); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new Reference(aptId.getValue())); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -675,9 +746,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new Reference(aptId.getValue())); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new Reference(aptId.getValue())); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -718,9 +789,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new Reference(aptId.getValue())); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new Reference(aptId.getValue())); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -755,9 +826,9 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu .addExtension() .setUrl("http://acme.org/foo"); extParent - .addExtension() - .setUrl("http://acme.org/bar") - .setValue(new StringType("HELLOHELLO")); + .addExtension() + .setUrl("http://acme.org/bar") + .setValue(new StringType("HELLOHELLO")); IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless(); @@ -861,7 +932,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu assertEquals("Unknown search parameter foo for resource type Patient", e.getMessage()); } } - + @Test public void testSearchWithCustomParamDraft() { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java index 5402caf8a7f..d6c93c27d97 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java @@ -71,23 +71,6 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test } } - @Test - public void testCreateInvalidParamMismatchedResourceName() { - SearchParameter fooSp = new SearchParameter(); - fooSp.addBase("Patient"); - fooSp.setCode("foo"); - fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN); - fooSp.setTitle("FOO SP"); - fooSp.setExpression("Patient.gender or Observation.code"); - fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL); - fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE); - try { - mySearchParameterDao.create(fooSp, mySrd); - fail(); - } catch (UnprocessableEntityException e) { - assertEquals("Invalid SearchParameter.expression value \"Observation.code\". All paths in a single SearchParameter must match the same resource type", e.getMessage()); - } - } @Test public void testCreateInvalidParamNoPath() { @@ -334,6 +317,77 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test }), empty()); } + /** + * See #863 + */ + @Test + public void testParamWithMultipleBases() { + SearchParameter sp = new SearchParameter(); + sp.setUrl("http://clinicalcloud.solutions/fhir/SearchParameter/request-reason"); + sp.setName("reason"); + sp.setStatus(Enumerations.PublicationStatus.ACTIVE); + sp.setCode("reason"); + sp.addBase("MedicationRequest"); + sp.addBase("ServiceRequest"); + sp.setType(Enumerations.SearchParamType.REFERENCE); + sp.setExpression("MedicationRequest.reasonReference | ServiceRequest.reasonReference"); + sp.addTarget("Condition"); + sp.addTarget("Observation"); + mySearchParameterDao.create(sp); + mySearchParamRegsitry.forceRefresh(); + + Condition condition = new Condition(); + condition.getCode().setText("A condition"); + String conditionId = myConditionDao.create(condition).getId().toUnqualifiedVersionless().getValue(); + + MedicationRequest mr = new MedicationRequest(); + mr.addReasonReference().setReference(conditionId); + String mrId = myMedicationRequestDao.create(mr).getId().toUnqualifiedVersionless().getValue(); + + ServiceRequest pr = new ServiceRequest(); + pr.addReasonReference().setReference(conditionId); + myServiceRequestDao.create(pr); + + SearchParameterMap map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add("reason", new ReferenceParam(conditionId)); + List results = toUnqualifiedVersionlessIdValues(myMedicationRequestDao.search(map)); + assertThat(results, contains(mrId)); + } + + + /** + * See #863 + */ + @Test + public void testParamWithMultipleBasesToken() { + SearchParameter sp = new SearchParameter(); + sp.setUrl("http://clinicalcloud.solutions/fhir/SearchParameter/request-reason"); + sp.setName("reason"); + sp.setStatus(Enumerations.PublicationStatus.ACTIVE); + sp.setCode("reason"); + sp.addBase("MedicationRequest"); + sp.addBase("ServiceRequest"); + sp.setType(Enumerations.SearchParamType.TOKEN); + sp.setExpression("MedicationRequest.reasonCode | ServiceRequest.reasonCode"); + mySearchParameterDao.create(sp); + mySearchParamRegsitry.forceRefresh(); + + MedicationRequest mr = new MedicationRequest(); + mr.addReasonCode().addCoding().setSystem("foo").setCode("bar"); + String mrId = myMedicationRequestDao.create(mr).getId().toUnqualifiedVersionless().getValue(); + + ServiceRequest pr = new ServiceRequest(); + pr.addReasonCode().addCoding().setSystem("foo").setCode("bar"); + myServiceRequestDao.create(pr); + + SearchParameterMap map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add("reason", new TokenParam("foo", "bar")); + List results = toUnqualifiedVersionlessIdValues(myMedicationRequestDao.search(map)); + assertThat(results, contains(mrId)); + } + @Test public void testSearchForExtensionReferenceWithNonMatchingTarget() { SearchParameter siblingSp = new SearchParameter(); diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java index bddc2103bff..54f95e22e24 100644 --- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java +++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java @@ -96,27 +96,29 @@ public class Controller extends BaseController { } @RequestMapping(value = { "/delete" }) - public String actionDelete(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) { - addCommonParams(theReq, theRequest, theModel); + public String actionDelete(HttpServletRequest theServletRequest, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) { + addCommonParams(theServletRequest, theRequest, theModel); CaptureInterceptor interceptor = new CaptureInterceptor(); - GenericClient client = theRequest.newClient(theReq, getContext(theRequest), myConfig, interceptor); + GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor); RuntimeResourceDefinition def; try { - def = getResourceType(theRequest, theReq); + def = getResourceType(theRequest, theServletRequest); } catch (ServletException e) { + populateModelForResource(theServletRequest, theRequest, theModel); theModel.put("errorMsg", toDisplayError(e.toString(), e)); return "resource"; } - String id = StringUtils.defaultString(theReq.getParameter("resource-delete-id")); + String id = StringUtils.defaultString(theServletRequest.getParameter("resource-delete-id")); if (StringUtils.isBlank(id)) { + populateModelForResource(theServletRequest, theRequest, theModel); theModel.put("errorMsg", toDisplayError("No ID specified", null)); return "resource"; } - ResultType returnsResource = ResultType.BUNDLE; + ResultType returnsResource = ResultType.RESOURCE; String outcomeDescription = "Delete Resource"; long start = System.currentTimeMillis(); @@ -192,27 +194,29 @@ public class Controller extends BaseController { } @RequestMapping(value = { "/read" }) - public String actionRead(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) { - addCommonParams(theReq, theRequest, theModel); + public String actionRead(HttpServletRequest theServletRequest, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) { + addCommonParams(theServletRequest, theRequest, theModel); CaptureInterceptor interceptor = new CaptureInterceptor(); - GenericClient client = theRequest.newClient(theReq, getContext(theRequest), myConfig, interceptor); + GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor); RuntimeResourceDefinition def; try { - def = getResourceType(theRequest, theReq); + def = getResourceType(theRequest, theServletRequest); } catch (ServletException e) { + populateModelForResource(theServletRequest, theRequest, theModel); theModel.put("errorMsg", toDisplayError(e.toString(), e)); return "resource"; } - String id = StringUtils.defaultString(theReq.getParameter("id")); + String id = StringUtils.defaultString(theServletRequest.getParameter("id")); if (StringUtils.isBlank(id)) { + populateModelForResource(theServletRequest, theRequest, theModel); theModel.put("errorMsg", toDisplayError("No ID specified", null)); return "resource"; } ResultType returnsResource = ResultType.RESOURCE; - String versionId = StringUtils.defaultString(theReq.getParameter("vid")); + String versionId = StringUtils.defaultString(theServletRequest.getParameter("vid")); String outcomeDescription; if (StringUtils.isBlank(versionId)) { versionId = null; @@ -242,45 +246,18 @@ public class Controller extends BaseController { @RequestMapping({ "/resource" }) public String actionResource(HttpServletRequest theServletRequest, final ResourceRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) { - IBaseResource conformance = addCommonParams(theServletRequest, theRequest, theModel); - - CaptureInterceptor interceptor = new CaptureInterceptor(); - GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor); String resourceName = theRequest.getResource(); - RuntimeResourceDefinition def = getContext(theRequest).getResourceDefinition(theRequest.getResource()); - TreeSet includes = new TreeSet(); - TreeSet revIncludes = new TreeSet(); - TreeSet sortParams = new TreeSet(); - boolean haveSearchParams = false; - List> queryIncludes = new ArrayList>(); - - switch (theRequest.getFhirVersion(myConfig)) { - case DSTU2: - haveSearchParams = extractSearchParamsDstu2(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes); - break; - case DSTU3: - haveSearchParams = extractSearchParamsDstu3CapabilityStatement(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes); - break; - case R4: - haveSearchParams = extractSearchParamsR4CapabilityStatement(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes); - break; - default: - throw new IllegalStateException("Unknown FHIR version: " + theRequest.getFhirVersion(myConfig)); - } - - theModel.put("includes", includes); - theModel.put("revincludes", revIncludes); - theModel.put("queries", Collections.emptyList()); // TODO: remove this, it does nothing - theModel.put("haveSearchParams", haveSearchParams); - theModel.put("queryIncludes", queryIncludes); - theModel.put("sortParams", sortParams); + populateModelForResource(theServletRequest, theRequest, theModel); if (isNotBlank(theRequest.getUpdateId())) { String updateId = theRequest.getUpdateId(); String updateVid = defaultIfEmpty(theRequest.getUpdateVid(), null); - IBaseResource updateResource = (IBaseResource) client.read(def.getImplementingClass(), new IdDt(resourceName, updateId, updateVid)); + CaptureInterceptor interceptor = new CaptureInterceptor(); + GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor); + RuntimeResourceDefinition def = getContext(theRequest).getResourceDefinition(theRequest.getResource()); + IBaseResource updateResource = client.read(def.getImplementingClass(), new IdDt(resourceName, updateId, updateVid)); String updateResourceString = theRequest.newParser(getContext(theRequest)).setPrettyPrint(true).encodeResourceToString(updateResource); theModel.put("updateResource", updateResourceString); theModel.put("updateResourceId", updateId); @@ -291,10 +268,43 @@ public class Controller extends BaseController { return "resource"; } + private void populateModelForResource(HttpServletRequest theServletRequest, HomeRequest theRequest, ModelMap theModel) { + IBaseResource conformance = addCommonParams(theServletRequest, theRequest, theModel); + + String resourceName = theRequest.getResource(); + + TreeSet includes = new TreeSet<>(); + TreeSet revIncludes = new TreeSet<>(); + TreeSet sortParams = new TreeSet<>(); + boolean haveSearchParams = false; + List> queryIncludes = new ArrayList<>(); + + switch (theRequest.getFhirVersion(myConfig)) { + case DSTU2: + haveSearchParams = extractSearchParamsDstu2(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes); + break; + case DSTU3: + haveSearchParams = extractSearchParamsDstu3CapabilityStatement(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes); + break; + case R4: + haveSearchParams = extractSearchParamsR4CapabilityStatement(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes); + break; + default: + throw new IllegalStateException("Unknown FHIR version: " + theRequest.getFhirVersion(myConfig)); + } + + theModel.put("includes", includes); + theModel.put("revincludes", revIncludes); + theModel.put("queries", Collections.emptyList()); // TODO: remove this, it does nothing + theModel.put("haveSearchParams", haveSearchParams); + theModel.put("queryIncludes", queryIncludes); + theModel.put("sortParams", sortParams); + } + @SuppressWarnings("unchecked") @RequestMapping(value = { "/search" }) - public String actionSearch(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) throws IOException { - addCommonParams(theReq, theRequest, theModel); + public String actionSearch(HttpServletRequest theServletRequest, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) throws IOException { + addCommonParams(theServletRequest, theRequest, theModel); StringWriter clientCodeJsonStringWriter = new StringWriter(); JsonWriter clientCodeJsonWriter = new JsonWriter(clientCodeJsonStringWriter); @@ -305,19 +315,20 @@ public class Controller extends BaseController { clientCodeJsonWriter.value((String) theModel.get("base")); CaptureInterceptor interceptor = new CaptureInterceptor(); - GenericClient client = theRequest.newClient(theReq, getContext(theRequest), myConfig, interceptor); + GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor); IUntypedQuery search = client.search(); IQuery query; - if (isNotBlank(theReq.getParameter("resource"))) { + if (isNotBlank(theServletRequest.getParameter("resource"))) { try { - query = search.forResource((Class) getResourceType(theRequest, theReq).getImplementingClass()); + query = search.forResource(getResourceType(theRequest, theServletRequest).getImplementingClass()); } catch (ServletException e) { + populateModelForResource(theServletRequest, theRequest, theModel); theModel.put("errorMsg", toDisplayError(e.toString(), e)); return "resource"; } clientCodeJsonWriter.name("resource"); - clientCodeJsonWriter.value(theReq.getParameter("resource")); + clientCodeJsonWriter.value(theServletRequest.getParameter("resource")); } else { query = search.forAllResources(); clientCodeJsonWriter.name("resource"); @@ -349,7 +360,7 @@ public class Controller extends BaseController { paramIdx++; String paramIdxString = Integer.toString(paramIdx); - boolean shouldContinue = handleSearchParam(paramIdxString, theReq, query, clientCodeJsonWriter); + boolean shouldContinue = handleSearchParam(paramIdxString, theServletRequest, query, clientCodeJsonWriter); if (!shouldContinue) { break; } @@ -358,7 +369,7 @@ public class Controller extends BaseController { clientCodeJsonWriter.name("includes"); clientCodeJsonWriter.beginArray(); - String[] incValues = theReq.getParameterValues(Constants.PARAM_INCLUDE); + String[] incValues = theServletRequest.getParameterValues(Constants.PARAM_INCLUDE); if (incValues != null) { for (String next : incValues) { if (isNotBlank(next)) { @@ -371,7 +382,7 @@ public class Controller extends BaseController { clientCodeJsonWriter.name("revincludes"); clientCodeJsonWriter.beginArray(); - String[] revIncValues = theReq.getParameterValues(Constants.PARAM_REVINCLUDE); + String[] revIncValues = theServletRequest.getParameterValues(Constants.PARAM_REVINCLUDE); if (revIncValues != null) { for (String next : revIncValues) { if (isNotBlank(next)) { @@ -382,9 +393,10 @@ public class Controller extends BaseController { } clientCodeJsonWriter.endArray(); - String limit = theReq.getParameter("resource-search-limit"); + String limit = theServletRequest.getParameter("resource-search-limit"); if (isNotBlank(limit)) { if (!limit.matches("[0-9]+")) { + populateModelForResource(theServletRequest, theRequest, theModel); theModel.put("errorMsg", toDisplayError("Search limit must be a numeric value.", null)); return "resource"; } @@ -397,13 +409,13 @@ public class Controller extends BaseController { clientCodeJsonWriter.nullValue(); } - String[] sort = theReq.getParameterValues("sort_by"); + String[] sort = theServletRequest.getParameterValues("sort_by"); if (sort != null) { for (String next : sort) { if (isBlank(next)) { continue; } - String direction = theReq.getParameter("sort_direction"); + String direction = theServletRequest.getParameter("sort_direction"); if ("asc".equals(direction)) { query.sort().ascending(new StringClientParam(next)); } else if ("desc".equals(direction)) { @@ -505,7 +517,7 @@ public class Controller extends BaseController { Class type = null; // def.getImplementingClass(); if ("history-type".equals(theMethod)) { RuntimeResourceDefinition def = getContext(theRequest).getResourceDefinition(theRequest.getResource()); - type = (Class) def.getImplementingClass(); + type = def.getImplementingClass(); } String body = validate ? theReq.getParameter("resource-validate-body") : theReq.getParameter("resource-create-body"); @@ -588,7 +600,7 @@ public class Controller extends BaseController { Class type = null; // def.getImplementingClass(); if ("history-type".equals(theMethod)) { RuntimeResourceDefinition def = getContext(theRequest).getResourceDefinition(theRequest.getResource()); - type = (Class) def.getImplementingClass(); + type = def.getImplementingClass(); id = StringUtils.defaultString(theReq.getParameter("resource-history-id")); } diff --git a/pom.xml b/pom.xml index ca332a176b3..00c25f54116 100644 --- a/pom.xml +++ b/pom.xml @@ -1118,8 +1118,8 @@ UTF-8 true - 128m - 1600m + 500m + 2000m diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c09699b15df..c1d29dce27b 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -150,6 +150,21 @@ elements of type "Reference". Thanks to GitHub user @t4deon for supplying a testcase! + + Deleting a resource from the testpage overlay resulted in an error page after + clicking "delete", even though the delete succeeded. + + + A number of info level log lines have been reduced to debug level in the JPA server, in + order to reduce contention during heavy loads. + + + JPA server now correctly indexes custom search parameters which + have multiple base resource types. Previously, the indexing could + cause resources of the wrong type to be returned in a search + if a parameter being used also matched that type. Thanks + to Dave Carlson for reporting! +