List of usage examples for java.util IdentityHashMap get
@SuppressWarnings("unchecked") public V get(Object key)
From source file:ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2.java
@SuppressWarnings("unchecked") private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) { BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum(); if (transactionType == BundleTypeEnum.BATCH) { return batch(theRequestDetails, theRequest); }// ww w . j av a 2 s. c o m if (transactionType == null) { String message = "Transactiion Bundle did not specify valid Bundle.type, assuming " + BundleTypeEnum.TRANSACTION.getCode(); ourLog.warn(message); transactionType = BundleTypeEnum.TRANSACTION; } if (transactionType != BundleTypeEnum.TRANSACTION) { throw new InvalidRequestException( "Unable to process transaction where incoming Bundle.type = " + transactionType.getCode()); } ourLog.info("Beginning {} with {} resources", theActionName, theRequest.getEntry().size()); long start = System.currentTimeMillis(); Date updateTime = new Date(); Set<IdDt> allIds = new LinkedHashSet<IdDt>(); Map<IdDt, IdDt> idSubstitutions = new HashMap<IdDt, IdDt>(); Map<IdDt, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdDt, DaoMethodOutcome>(); /* * We want to execute the transaction request bundle elements in the order * specified by the FHIR specification (see TransactionSorter) so we save the * original order in the request, then sort it. * * Entries with a type of GET are removed from the bundle so that they * can be processed at the very end. We do this because the incoming resources * are saved in a two-phase way in order to deal with interdependencies, and * we want the GET processing to use the final indexing state */ Bundle response = new Bundle(); List<Entry> getEntries = new ArrayList<Entry>(); IdentityHashMap<Entry, Integer> originalRequestOrder = new IdentityHashMap<Bundle.Entry, Integer>(); for (int i = 0; i < theRequest.getEntry().size(); i++) { originalRequestOrder.put(theRequest.getEntry().get(i), i); response.addEntry(); if (theRequest.getEntry().get(i).getRequest().getMethodElement().getValueAsEnum() == HTTPVerbEnum.GET) { getEntries.add(theRequest.getEntry().get(i)); } } Collections.sort(theRequest.getEntry(), new TransactionSorter()); List<IIdType> deletedResources = new ArrayList<IIdType>(); List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>(); Map<Entry, ResourceTable> entriesToProcess = new IdentityHashMap<Entry, ResourceTable>(); Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>(); /* * Loop through the request and process any entries of type * PUT, POST or DELETE */ for (int i = 0; i < theRequest.getEntry().size(); i++) { if (i % 100 == 0) { ourLog.info("Processed {} non-GET entries out of {}", i, theRequest.getEntry().size()); } Entry nextReqEntry = theRequest.getEntry().get(i); IResource res = nextReqEntry.getResource(); IdDt nextResourceId = null; if (res != null) { nextResourceId = res.getId(); if (nextResourceId.hasIdPart() == false) { if (isNotBlank(nextReqEntry.getFullUrl())) { nextResourceId = new IdDt(nextReqEntry.getFullUrl()); } } if (nextResourceId.hasIdPart() && nextResourceId.getIdPart().matches("[a-zA-Z]+\\:.*") && !isPlaceholder(nextResourceId)) { throw new InvalidRequestException("Invalid placeholder ID found: " + nextResourceId.getIdPart() + " - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'"); } if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType() && !isPlaceholder(nextResourceId)) { nextResourceId = new IdDt(toResourceName(res.getClass()), nextResourceId.getIdPart()); res.setId(nextResourceId); } /* * Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness */ if (isPlaceholder(nextResourceId)) { if (!allIds.add(nextResourceId)) { throw new InvalidRequestException( getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId)); } } else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) { IdDt nextId = nextResourceId.toUnqualifiedVersionless(); if (!allIds.add(nextId)) { throw new InvalidRequestException(getContext().getLocalizer().getMessage( BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId)); } } } HTTPVerbEnum verb = nextReqEntry.getRequest().getMethodElement().getValueAsEnum(); if (verb == null) { throw new InvalidRequestException( getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionEntryHasInvalidVerb", nextReqEntry.getRequest().getMethod())); } String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null; Entry nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry)); switch (verb) { case POST: { // CREATE @SuppressWarnings("rawtypes") IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); res.setId((String) null); DaoMethodOutcome outcome; outcome = resourceDao.create(res, nextReqEntry.getRequest().getIfNoneExist(), false, theRequestDetails); handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res); entriesToProcess.put(nextRespEntry, outcome.getEntity()); if (outcome.getCreated() == false) { nonUpdatedEntities.add(outcome.getEntity()); } break; } case DELETE: { // DELETE String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); UrlParts parts = UrlUtil.parseUrl(url); ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.getCode(), url); int status = Constants.STATUS_HTTP_204_NO_CONTENT; if (parts.getResourceId() != null) { ResourceTable deleted = dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()), deleteConflicts, theRequestDetails); if (deleted != null) { deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless()); } } else { List<ResourceTable> allDeleted = dao.deleteByUrl( parts.getResourceType() + '?' + parts.getParams(), deleteConflicts, theRequestDetails); for (ResourceTable deleted : allDeleted) { deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless()); } if (allDeleted.isEmpty()) { status = Constants.STATUS_HTTP_404_NOT_FOUND; } } nextRespEntry.getResponse().setStatus(toStatusString(status)); break; } case PUT: { // UPDATE @SuppressWarnings("rawtypes") IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass()); DaoMethodOutcome outcome; String url = extractTransactionUrlOrThrowException(nextReqEntry, verb); UrlParts parts = UrlUtil.parseUrl(url); if (isNotBlank(parts.getResourceId())) { res.setId(new IdDt(parts.getResourceType(), parts.getResourceId())); outcome = resourceDao.update(res, null, false, theRequestDetails); } else { res.setId((String) null); outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false, theRequestDetails); } handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res); entriesToProcess.put(nextRespEntry, outcome.getEntity()); break; } } } /* * Make sure that there are no conflicts from deletions. E.g. we can't delete something * if something else has a reference to it.. Unless the thing that has a reference to it * was also deleted as a part of this transaction, which is why we check this now at the * end. */ for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext();) { DeleteConflict next = iter.next(); if (deletedResources.contains(next.getTargetId().toVersionless())) { iter.remove(); } } validateDeleteConflictsEmptyOrThrowException(deleteConflicts); /* * Perform ID substitutions and then index each resource we have saved */ FhirTerser terser = getContext().newTerser(); for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) { IResource nextResource = (IResource) nextOutcome.getResource(); if (nextResource == null) { continue; } List<BaseResourceReferenceDt> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, BaseResourceReferenceDt.class); for (BaseResourceReferenceDt nextRef : allRefs) { IdDt nextId = nextRef.getReference(); if (!nextId.hasIdPart()) { continue; } if (idSubstitutions.containsKey(nextId)) { IdDt newId = idSubstitutions.get(nextId); ourLog.info(" * Replacing resource ref {} with {}", nextId, newId); nextRef.setReference(newId); } else { ourLog.debug(" * Reference [{}] does not exist in bundle", nextId); } } InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource); Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null; boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity()); updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, shouldUpdate, updateTime); } myEntityManager.flush(); /* * Double check we didn't allow any duplicates we shouldn't have */ for (Entry nextEntry : theRequest.getEntry()) { if (nextEntry.getRequest().getMethodElement().getValueAsEnum() == HTTPVerbEnum.POST) { String matchUrl = nextEntry.getRequest().getIfNoneExist(); if (isNotBlank(matchUrl)) { IFhirResourceDao<?> resourceDao = getDao(nextEntry.getResource().getClass()); Set<Long> val = resourceDao.processMatchUrl(matchUrl); if (val.size() > 1) { throw new InvalidRequestException("Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?"); } } } } for (IdDt next : allIds) { IdDt replacement = idSubstitutions.get(next); if (replacement == null) { continue; } if (replacement.equals(next)) { continue; } ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement); } /* * Loop through the request and process any entries of type GET */ for (int i = 0; i < getEntries.size(); i++) { Entry nextReqEntry = getEntries.get(i); Integer originalOrder = originalRequestOrder.get(nextReqEntry); Entry nextRespEntry = response.getEntry().get(originalOrder); ServletSubRequestDetails requestDetails = new ServletSubRequestDetails(); requestDetails.setServletRequest(theRequestDetails.getServletRequest()); requestDetails.setRequestType(RequestTypeEnum.GET); requestDetails.setServer(theRequestDetails.getServer()); String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerbEnum.GET); int qIndex = url.indexOf('?'); ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create(); requestDetails.setParameters(new HashMap<String, String[]>()); if (qIndex != -1) { String params = url.substring(qIndex); List<NameValuePair> parameters = translateMatchUrl(params); for (NameValuePair next : parameters) { paramValues.put(next.getName(), next.getValue()); } for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap() .entrySet()) { String[] nextValue = nextParamEntry.getValue() .toArray(new String[nextParamEntry.getValue().size()]); requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue); } url = url.substring(0, qIndex); } requestDetails.setRequestPath(url); requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase()); theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url); BaseMethodBinding<?> method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url); if (method == null) { throw new IllegalArgumentException("Unable to handle GET " + url); } if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) { requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch()); } if (isNotBlank(nextReqEntry.getRequest().getIfNoneExist())) { requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextReqEntry.getRequest().getIfNoneExist()); } if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) { requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch()); } if (method instanceof BaseResourceReturningMethodBinding) { try { ResourceOrDstu1Bundle responseData = ((BaseResourceReturningMethodBinding) method) .doInvokeServer(theRequestDetails.getServer(), requestDetails); IBaseResource resource = responseData.getResource(); if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) { resource = filterNestedBundle(requestDetails, resource); } nextRespEntry.setResource((IResource) resource); nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK)); } catch (NotModifiedException e) { nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED)); } } else { throw new IllegalArgumentException("Unable to handle GET " + url); } } ourLog.info("Flushing context after {}", theActionName); myEntityManager.flush(); for (java.util.Map.Entry<Entry, ResourceTable> nextEntry : entriesToProcess.entrySet()) { nextEntry.getKey().getResponse().setLocation(nextEntry.getValue().getIdDt().toUnqualified().getValue()); nextEntry.getKey().getResponse().setEtag(nextEntry.getValue().getIdDt().getVersionIdPart()); } long delay = System.currentTimeMillis() - start; int numEntries = theRequest.getEntry().size(); long delayPer = delay / numEntries; ourLog.info("{} completed in {}ms ({} entries at {}ms per entry)", new Object[] { theActionName, delay, numEntries, delayPer }); response.setType(BundleTypeEnum.TRANSACTION_RESPONSE); return response; }