ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings.java Source code

Java tutorial

Introduction

Here is the source code for ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings.java

Source

package ca.uhn.fhir.jaxrs.server.util;

/*
 * #%L
 * HAPI FHIR JAX-RS Server
 * %%
 * 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 java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.OperationMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding;
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
import ca.uhn.fhir.util.ReflectionUtil;

/**
 * Class that contains the method bindings defined by a ResourceProvider
 * 
 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
 */
public class JaxRsMethodBindings {

    /** DEFAULT_METHOD_KEY="" */
    public static final String DEFAULT_METHOD_KEY = "";
    /** Static collection of bindings mapped to a class*/
    private static final ConcurrentHashMap<Class<?>, JaxRsMethodBindings> classBindings = new ConcurrentHashMap<Class<?>, JaxRsMethodBindings>();
    /** Static collection of operationBindings mapped to a class */
    private ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String, BaseMethodBinding<?>>> operationBindings = new ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String, BaseMethodBinding<?>>>();

    /**
     * The constructor
     * @param theProvider the provider which is an implementation of the theProviderClass
     * @param theProviderClass the class definition contaning the operations 
     */
    public JaxRsMethodBindings(AbstractJaxRsProvider theProvider,
            Class<? extends AbstractJaxRsProvider> theProviderClass) {
        for (final Method m : ReflectionUtil.getDeclaredMethods(theProviderClass)) {
            final BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m,
                    theProvider.getFhirContext(), theProvider);
            if (foundMethodBinding == null) {
                continue;
            }
            String bindingKey = getBindingKey(foundMethodBinding);
            addMethodBinding(bindingKey, foundMethodBinding);
        }
    }

    /**
     * Get the key for the baseMethodBinding. This is:
     * <ul>
     *    <li>the compartName for SearchMethodBindings
     *    <li>the methodName for OperationMethodBindings
     *    <li> {@link #DEFAULT_METHOD_KEY} for all other MethodBindings 
     * </ul>
     * @param theBinding the methodbinding
     * @return the key for the methodbinding.
     */
    private String getBindingKey(final BaseMethodBinding<?> theBinding) {
        if (theBinding instanceof OperationMethodBinding) {
            return ((OperationMethodBinding) theBinding).getName();
        } else if (theBinding instanceof SearchMethodBinding) {
            Search search = theBinding.getMethod().getAnnotation(Search.class);
            return search.compartmentName();
        } else {
            return DEFAULT_METHOD_KEY;
        }
    }

    private void addMethodBinding(String key, BaseMethodBinding<?> binding) {
        ConcurrentHashMap<String, BaseMethodBinding<?>> mapByOperation = getMapForOperation(
                binding.getRestOperationType());
        if (mapByOperation.containsKey(key)) {
            throw new IllegalArgumentException("Multiple Search Method Bindings Found : " + mapByOperation.get(key)
                    + " -- " + binding.getMethod());
        }
        mapByOperation.put(key, binding);
    }

    /**
     * Get the map for the given operation type. If no map exists for this operation type, create a new hashmap for this
     * operation type and add it to the operation bindings.
     * 
     * @param operationType the operation type.
     * @return the map defined in the operation bindings
     */
    private ConcurrentHashMap<String, BaseMethodBinding<?>> getMapForOperation(
            RestOperationTypeEnum operationType) {
        ConcurrentHashMap<String, BaseMethodBinding<?>> result = operationBindings.get(operationType);
        if (result == null) {
            operationBindings.putIfAbsent(operationType, new ConcurrentHashMap<String, BaseMethodBinding<?>>());
            return getMapForOperation(operationType);
        } else {
            return result;
        }
    }

    /**
     * Get the binding 
     * 
     * @param operationType the type of operation
     * @param theBindingKey the binding key
     * @return the binding defined
     * @throws NotImplementedOperationException cannot be found
     */
    public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType, String theBindingKey) {
        String bindingKey = StringUtils.defaultIfBlank(theBindingKey, DEFAULT_METHOD_KEY);
        ConcurrentHashMap<String, BaseMethodBinding<?>> map = operationBindings.get(operationType);
        if (map == null || !map.containsKey(bindingKey)) {
            throw new NotImplementedOperationException("Operation not implemented");
        } else {
            return map.get(bindingKey);
        }
    }

    /**
     * Get the method bindings for the given class. If this class is not yet contained in the classBindings, they will be added for this class
     * 
     * @param theProvider the implementation class
     * @param theProviderClass the provider class
     * @return the methodBindings for this class
     */
    public static JaxRsMethodBindings getMethodBindings(AbstractJaxRsProvider theProvider,
            Class<? extends AbstractJaxRsProvider> theProviderClass) {
        if (!getClassBindings().containsKey(theProviderClass)) {
            JaxRsMethodBindings foundBindings = new JaxRsMethodBindings(theProvider, theProviderClass);
            getClassBindings().putIfAbsent(theProviderClass, foundBindings);
        }
        return getClassBindings().get(theProviderClass);
    }

    /**
     * @return the classBindings
     */
    static ConcurrentHashMap<Class<?>, JaxRsMethodBindings> getClassBindings() {
        return classBindings;
    }

}