Example usage for java.util IdentityHashMap get

List of usage examples for java.util IdentityHashMap get

Introduction

In this page you can find the example usage for java.util IdentityHashMap get.

Prototype

@SuppressWarnings("unchecked")
public V get(Object key) 

Source Link

Document

Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.

Usage

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;
}