diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/cache/ResourceVersionSvcDaoImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/cache/ResourceVersionSvcDaoImpl.java index c9ca8e0255a..3aa68936218 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/cache/ResourceVersionSvcDaoImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/cache/ResourceVersionSvcDaoImpl.java @@ -37,7 +37,10 @@ import org.springframework.stereotype.Service; import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import static org.slf4j.LoggerFactory.getLogger; @@ -80,11 +83,93 @@ public class ResourceVersionSvcDaoImpl implements IResourceVersionSvc { } @Override - public ResourcePersistentIdMap getLatestVersionIdsForResourceIds(RequestPartitionId thePartitionId, List theIds) { + /** + * Retrieves the latest versions for any resourceid that are found. + * If they are not found, they will not be contained in the returned map. + * The key should be the same value that was passed in to allow + * consumer to look up the value using the id they already have. + * + * This method should not throw, so it can safely be consumed in + * transactions. + * + * @param theRequestPartitionId - request partition id + * @param theIds - list of IIdTypes for resources of interest. + * @return + */ + public ResourcePersistentIdMap getLatestVersionIdsForResourceIds(RequestPartitionId theRequestPartitionId, List theIds) { + ResourcePersistentIdMap idToPID = new ResourcePersistentIdMap(); + HashMap> resourceTypeToIds = new HashMap<>(); + + for (IIdType id : theIds) { + String resourceType = id.getResourceType(); + if (!resourceTypeToIds.containsKey(resourceType)) { + resourceTypeToIds.put(resourceType, new ArrayList<>()); + } + resourceTypeToIds.get(resourceType).add(id); + } + + for (String resourceType : resourceTypeToIds.keySet()) { + ResourcePersistentIdMap idAndPID = getIdsOfExistingResources(theRequestPartitionId, + resourceTypeToIds.get(resourceType)); + idToPID.putAll(idAndPID); + } + + return idToPID; + } + + /** + * Helper method to determine if some resources exist in the DB (without throwing). + * Returns a set that contains the IIdType for every resource found. + * If it's not found, it won't be included in the set. + * + * @param theIds - list of IIdType ids (for the same resource) + * @return + */ + private ResourcePersistentIdMap getIdsOfExistingResources(RequestPartitionId thePartitionId, + Collection theIds) { + // these are the found Ids that were in the db + ResourcePersistentIdMap retval = new ResourcePersistentIdMap(); + + if (theIds == null || theIds.isEmpty()) { + return retval; + } List resourcePersistentIds = myIdHelperService.resolveResourcePersistentIdsWithCache(thePartitionId, - new ArrayList<>(theIds)); + theIds.stream().collect(Collectors.toList())); - return ResourcePersistentIdMap.fromResourcePersistentIds(resourcePersistentIds); + // we'll use this map to fetch pids that require versions + HashMap pidsToVersionToResourcePid = new HashMap<>(); + + // fill in our map + for (ResourcePersistentId pid : resourcePersistentIds) { + if (pid.getVersion() == null) { + pidsToVersionToResourcePid.put(pid.getIdAsLong(), pid); + } + Optional idOp = theIds.stream() + .filter(i -> i.getIdPart().equals(pid.getAssociatedResourceId().getIdPart())) + .findFirst(); + // this should always be present + // since it was passed in. + // but land of optionals... + idOp.ifPresent(id -> { + retval.put(id, pid); + }); + } + + // set any versions we don't already have + if (!pidsToVersionToResourcePid.isEmpty()) { + Collection resourceEntries = myResourceTableDao + .getResourceVersionsForPid(new ArrayList<>(pidsToVersionToResourcePid.keySet())); + + for (Object[] record : resourceEntries) { + // order matters! + Long retPid = (Long) record[0]; + String resType = (String) record[1]; + Long version = (Long) record[2]; + pidsToVersionToResourcePid.get(retPid).setVersion(version); + } + } + + return retval; } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/elastic/IndexNamePrefixLayoutStrategy.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/elastic/IndexNamePrefixLayoutStrategy.java index fa5721b75dc..f0849bd1b22 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/elastic/IndexNamePrefixLayoutStrategy.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/elastic/IndexNamePrefixLayoutStrategy.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.search.elastic; +/*- + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.jpa.api.config.DaoConfig; import org.apache.commons.lang3.StringUtils; @@ -24,7 +44,7 @@ public class IndexNamePrefixLayoutStrategy implements IndexLayoutStrategy { @Autowired private DaoConfig myDaoConfig; - static final Log log = (Log) LoggerFactory.make(Log.class, MethodHandles.lookup()); + static final Log log = LoggerFactory.make(Log.class, MethodHandles.lookup()); public static final String NAME = "prefix"; public static final Pattern UNIQUE_KEY_EXTRACTION_PATTERN = Pattern.compile("(.*)-\\d{6}"); diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/cache/ResourcePersistentIdMap.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/cache/ResourcePersistentIdMap.java index 6a723db0606..6594bc723b2 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/cache/ResourcePersistentIdMap.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/cache/ResourcePersistentIdMap.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.cache; +/*- + * #%L + * HAPI FHIR Search Parameters + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; import org.hl7.fhir.instance.model.api.IIdType; @@ -36,4 +56,12 @@ public class ResourcePersistentIdMap { public int size() { return myMap.size(); } + + public void put(IIdType theId, ResourcePersistentId thePid) { + myMap.put(theId, thePid); + } + + public void putAll(ResourcePersistentIdMap theIdAndPID) { + myMap.putAll(theIdAndPID.myMap); + } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmBatchJobSubmitterFactory.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmBatchJobSubmitterFactory.java index 6291d89d99a..6dc629d0f05 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmBatchJobSubmitterFactory.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmBatchJobSubmitterFactory.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.mdm.api; +/*- + * #%L + * HAPI FHIR - Master Data Management + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + public interface IMdmBatchJobSubmitterFactory { IMdmClearJobSubmitter getClearJobSubmitter(); } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/ResourcePersistentId.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/ResourcePersistentId.java index 79a622e268f..020c043d866 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/ResourcePersistentId.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/storage/ResourcePersistentId.java @@ -21,7 +21,7 @@ package ca.uhn.fhir.rest.api.server.storage; */ import ca.uhn.fhir.util.ObjectUtil; -import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IIdType; import java.util.ArrayList; @@ -34,6 +34,7 @@ import java.util.Optional; * a Long, a String, or something else. */ public class ResourcePersistentId { + private static final String RESOURCE_PID = "RESOURCE_PID"; private Object myId; private Long myVersion; private IIdType myAssociatedResourceId; @@ -127,9 +128,9 @@ public class ResourcePersistentId { return retVal; } - public static ResourcePersistentId fromResource(IBaseResource theResource) { + public static ResourcePersistentId fromResource(IAnyResource theResource) { IIdType id = theResource.getIdElement(); - ResourcePersistentId retval = new ResourcePersistentId(id.getIdPart()); + ResourcePersistentId retval = new ResourcePersistentId(theResource.getUserData(RESOURCE_PID)); retval.setAssociatedResourceId(id); retval.setVersion(id.getVersionIdPartAsLong()); return retval;