ca.uhn.fhir.rest.method.HistoryMethodBinding.java Source code

Java tutorial

Introduction

Here is the source code for ca.uhn.fhir.rest.method.HistoryMethodBinding.java

Source

package ca.uhn.fhir.rest.method;

/*
 * #%L
 * HAPI FHIR - Core Library
 * %%
 * Copyright (C) 2014 - 2016 University Health Network
 * %%
 * 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 static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {

    private final Integer myIdParamIndex;
    private String myResourceName;
    private final RestOperationTypeEnum myResourceOperationType;

    public HistoryMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
        super(toReturnType(theMethod, theProvider), theMethod, theContext, theProvider);

        myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());

        History historyAnnotation = theMethod.getAnnotation(History.class);
        Class<? extends IBaseResource> type = historyAnnotation.type();
        if (Modifier.isInterface(type.getModifiers())) {
            if (theProvider instanceof IResourceProvider) {
                type = ((IResourceProvider) theProvider).getResourceType();
                if (myIdParamIndex != null) {
                    myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
                } else {
                    myResourceOperationType = RestOperationTypeEnum.HISTORY_TYPE;
                }
            } else {
                myResourceOperationType = RestOperationTypeEnum.HISTORY_SYSTEM;
            }
        } else {
            if (myIdParamIndex != null) {
                myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
            } else {
                myResourceOperationType = RestOperationTypeEnum.HISTORY_TYPE;
            }
        }

        if (type != IResource.class) {
            myResourceName = theContext.getResourceDefinition(type).getName();
        } else {
            myResourceName = null;
        }

    }

    @Override
    public RestOperationTypeEnum getRestOperationType() {
        return myResourceOperationType;
    }

    @Override
    protected BundleTypeEnum getResponseBundleType() {
        return BundleTypeEnum.HISTORY;
    }

    @Override
    public ReturnTypeEnum getReturnType() {
        return ReturnTypeEnum.BUNDLE;
    }

    // ObjectUtils.equals is replaced by a JDK7 method..
    @Override
    public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
        if (!Constants.PARAM_HISTORY.equals(theRequest.getOperation())) {
            return false;
        }
        if (theRequest.getResourceName() == null) {
            return myResourceOperationType == RestOperationTypeEnum.HISTORY_SYSTEM;
        }
        if (!StringUtils.equals(theRequest.getResourceName(), myResourceName)) {
            return false;
        }

        boolean haveIdParam = theRequest.getId() != null && !theRequest.getId().isEmpty();
        boolean wantIdParam = myIdParamIndex != null;
        if (haveIdParam != wantIdParam) {
            return false;
        }

        if (theRequest.getId() == null) {
            return myResourceOperationType == RestOperationTypeEnum.HISTORY_TYPE;
        } else if (theRequest.getId().hasVersionIdPart()) {
            return false;
        }

        return true;
    }

    @Override
    public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
        IdDt id = null;
        String resourceName = myResourceName;
        if (myIdParamIndex != null) {
            id = (IdDt) theArgs[myIdParamIndex];
            if (id == null || isBlank(id.getValue())) {
                throw new NullPointerException("ID can not be null");
            }
        }

        String historyId = id != null ? id.getIdPart() : null;
        HttpGetClientInvocation retVal = createHistoryInvocation(getContext(), resourceName, historyId, null, null);

        if (theArgs != null) {
            for (int idx = 0; idx < theArgs.length; idx++) {
                IParameter nextParam = getParameters().get(idx);
                nextParam.translateClientArgumentIntoQueryArgument(getContext(), theArgs[idx],
                        retVal.getParameters(), null);
            }
        }

        return retVal;
    }

    @Override
    public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest,
            Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
        if (myIdParamIndex != null) {
            theMethodParams[myIdParamIndex] = theRequest.getId();
        }

        Object response = invokeServerMethod(theServer, theRequest, theMethodParams);

        final IBundleProvider resources = toResourceList(response);

        /*
         * We wrap the response so we can verify that it has the ID and version set,
         * as is the contract for history
         */
        return new IBundleProvider() {

            @Override
            public InstantDt getPublished() {
                return resources.getPublished();
            }

            @Override
            public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
                List<IBaseResource> retVal = resources.getResources(theFromIndex, theToIndex);
                int index = theFromIndex;
                for (IBaseResource nextResource : retVal) {
                    if (nextResource.getIdElement() == null || isBlank(nextResource.getIdElement().getIdPart())) {
                        throw new InternalErrorException("Server provided resource at index " + index
                                + " with no ID set (using IResource#setId(IdDt))");
                    }
                    if (isBlank(nextResource.getIdElement().getVersionIdPart())
                            && nextResource instanceof IResource) {
                        IdDt versionId = (IdDt) ResourceMetadataKeyEnum.VERSION_ID.get((IResource) nextResource);
                        if (versionId == null || versionId.isEmpty()) {
                            throw new InternalErrorException("Server provided resource at index " + index
                                    + " with no Version ID set (using IResource#setId(IdDt))");
                        }
                    }
                    index++;
                }
                return retVal;
            }

            @Override
            public int size() {
                return resources.size();
            }

            @Override
            public Integer preferredPageSize() {
                return null;
            }
        };
    }

    public static HttpGetClientInvocation createHistoryInvocation(FhirContext theContext, String theResourceName,
            String theId, IPrimitiveType<Date> theSince, Integer theLimit) {
        StringBuilder b = new StringBuilder();
        if (theResourceName != null) {
            b.append(theResourceName);
            if (isNotBlank(theId)) {
                b.append('/');
                b.append(theId);
            }
        }
        if (b.length() > 0) {
            b.append('/');
        }
        b.append(Constants.PARAM_HISTORY);

        boolean haveParam = false;
        if (theSince != null && !theSince.isEmpty()) {
            haveParam = true;
            b.append('?').append(Constants.PARAM_SINCE).append('=').append(theSince.getValueAsString());
        }
        if (theLimit != null) {
            b.append(haveParam ? '&' : '?');
            b.append(Constants.PARAM_COUNT).append('=').append(theLimit);
        }

        HttpGetClientInvocation retVal = new HttpGetClientInvocation(theContext, b.toString());
        return retVal;
    }

    private static Class<? extends IBaseResource> toReturnType(Method theMethod, Object theProvider) {
        if (theProvider instanceof IResourceProvider) {
            return ((IResourceProvider) theProvider).getResourceType();
        }
        History historyAnnotation = theMethod.getAnnotation(History.class);
        Class<? extends IResource> type = historyAnnotation.type();
        if (type != IResource.class) {
            return type;
        }
        return null;
    }

}