org.openmrs.module.reportingrest.util.ParameterUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.reportingrest.util.ParameterUtil.java

Source

/*
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */

package org.openmrs.module.reportingrest.util;

import org.apache.commons.beanutils.PropertyUtils;
import org.openmrs.api.APIException;
import org.openmrs.api.context.Context;
import org.openmrs.module.reporting.evaluation.parameter.Mapped;
import org.openmrs.module.reporting.evaluation.parameter.Parameter;
import org.openmrs.module.reporting.evaluation.parameter.Parameterizable;
import org.openmrs.module.webservices.rest.web.ConversionUtil;
import org.openmrs.module.webservices.rest.web.api.RestService;
import org.openmrs.module.webservices.rest.web.resource.api.Resource;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ParameterUtil {

    /**
     * Converts simple JSON types to the correct types as specified in _parameters_.
     *
     * This supports the scenario where a REST client submits a minimal representation of an object by looking up the
     * real object, and not just converting the submitted object's properties, e.g. you could submit an encounter type
     * that looks like {"display": "Emergency", "uuid": "07000be2-26b6-4cce-8b40-866d8435b613"} or even just
     * "07000be2-26b6-4cce-8b40-866d8435b613"
     *
     * @param parameters
     * @param parameterValues
     * @return
     */
    public static Map<String, Object> convertParameterValues(List<Parameter> parameters,
            Map<String, Object> parameterValues) throws Exception {
        if (parameterValues == null) {
            return null;
        }
        Map<String, Object> convertedParameterValues = new HashMap<String, Object>();
        for (Map.Entry<String, Object> entry : parameterValues.entrySet()) {
            Parameter parameter = findParameterByName(parameters, entry.getKey());
            if (parameter != null) {
                Resource resource = getResourceFor(parameter.getType());
                Object convertedValue;
                if (parameter.getCollectionType() != null) {
                    Collection target = newCollectionFor(parameter);
                    if (resource != null) {
                        // use the resource for this type, assuming a uuid for minimal representation was submitted
                        List original = (List) entry.getValue();
                        for (Object item : original) {
                            target.add(getRealInstanceByUuid(resource, item));
                        }
                        convertedValue = target;
                    } else {
                        // no resource for this type, so it's probably a simple type (date, etc), and we use the REST
                        // module's ConversionUtil to convert it

                        // this looks hacky, but there's no good way to construct a ParameterizedType at run-time; the only
                        // way I know to programmatically construct something like a collection with type information is by
                        // using an array
                        Class<?> arrayClass = Array.newInstance(parameter.getType(), 0).getClass();
                        Object array = ConversionUtil.convert(entry.getValue(), arrayClass);

                        int length = Array.getLength(array);
                        for (int i = 0; i < length; ++i) {
                            target.add(Array.get(array, i));
                        }
                        convertedValue = target;
                    }
                } else { // single value, not collection
                    if (resource != null) {
                        // use the resource for this type, assuming a uuid for minimal representation was submitted
                        convertedValue = getRealInstanceByUuid(resource, entry.getValue());
                    } else {
                        // no resource for this type, so it's probably a simple type (date, etc), and we use the REST
                        // module's ConversionUtil to convert it
                        convertedValue = ConversionUtil.convert(entry.getValue(), parameter.getType());
                    }
                }

                convertedParameterValues.put(entry.getKey(), convertedValue);
            }
        }

        return convertedParameterValues;
    }

    /**
     * Expects you to pass in a String UUID, or else an object with a String "uuid" property.
     * Also assumes that resource is a conventional OpenMRS implementation, with a "getByUniqueId" method
     * @param resource
     * @param item
     * @return
     */
    private static Object getRealInstanceByUuid(Resource resource, Object item) {
        try {
            Method method = getByUniqueIdMethod(resource);
            String uuid = (String) (item instanceof String ? item : PropertyUtils.getProperty(item, "uuid"));
            return method.invoke(resource, uuid);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to find item=" + item + " using resource=" + resource, e);
        }
    }

    private static Method getByUniqueIdMethod(Resource resource) {
        try {
            return resource.getClass().getMethod("getByUniqueId", String.class);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    private static Collection newCollectionFor(Parameter parameter) {
        Class<? extends Collection> collectionType = parameter.getCollectionType();
        return collectionType == null ? null : collectionType.equals(Set.class) ? new HashSet() : new ArrayList();
    }

    private static Resource getResourceFor(Class<?> type) {
        try {
            return Context.getService(RestService.class).getResourceBySupportedClass(type);
        } catch (APIException ex) {
            // e.g. org.openmrs.api.A#PIException: Unknown resource: class java.util.Date
            return null;
        }
    }

    private static Parameter findParameterByName(List<Parameter> parameters, String name) {
        for (Parameter parameter : parameters) {
            if (parameter.getName().equals(name)) {
                return parameter;
            }
        }
        return null;
    }

    /**
     * If any parameters on mapped.parameterizable are not explicitly mapped, they will be mapped to ${paramName}
     * @param mapped
     */
    public static void mapMissingParametersStraightThrough(Mapped<? extends Parameterizable> mapped) {
        Map<String, Object> mappings = mapped.getParameterMappings();
        Parameterizable parameterizable = mapped.getParameterizable();
        for (Parameter parameter : parameterizable.getParameters()) {
            if (mappings.get(parameter.getName()) == null) {
                mappings.put(parameter.getName(), parameter.getExpression());
            }
        }
    }

}