edu.cornell.kfs.sys.web.controller.DataObjectRestServiceController.java Source code

Java tutorial

Introduction

Here is the source code for edu.cornell.kfs.sys.web.controller.DataObjectRestServiceController.java

Source

/*
 * Copyright 2014 The Kuali Foundation.
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.
 */
package edu.cornell.kfs.sys.web.controller;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kuali.kfs.coreservice.framework.parameter.ParameterService;
import org.kuali.kfs.kns.datadictionary.InquirySectionDefinition;
import org.kuali.kfs.kns.lookup.LookupableHelperService;
import org.kuali.kfs.krad.service.DataDictionaryService;
import org.kuali.kfs.krad.service.KRADServiceLocator;
import org.kuali.kfs.krad.service.KRADServiceLocatorWeb;
import org.kuali.kfs.krad.service.PersistenceStructureService;
import org.kuali.kfs.krad.service.XmlObjectSerializerService;
import org.kuali.kfs.krad.util.GlobalVariables;
import org.kuali.kfs.krad.util.KRADConstants;
import org.kuali.kfs.krad.util.KRADUtils;
import org.kuali.kfs.krad.util.ObjectUtils;
import org.kuali.kfs.sys.businessobject.datadictionary.FinancialSystemBusinessObjectEntry;
import org.kuali.kfs.sys.businessobject.lookup.LookupableSpringContext;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
import org.kuali.rice.core.api.util.type.TypeUtils;
import org.kuali.rice.kim.api.KimConstants;
import org.kuali.rice.kim.api.permission.PermissionService;
import org.kuali.rice.kim.api.services.KimApiServiceLocator;
import org.kuali.rice.krad.bo.BusinessObject;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import edu.cornell.kfs.sys.util.RestXmlUtil;

@Controller
public class DataObjectRestServiceController {

    private static final String LOOKUPABLE_HELPER_SERVICE = "cf.lookupableHelperService";
    private static final String MAX_OBJECTS_TO_RETURN = "maxObjectsToReturn";
    private static final String LIMIT_BY_PARAMETER = "limitByParameter";

    private static final Logger LOG = LogManager.getLogger(DataObjectRestServiceController.class);

    private DataDictionaryService dataDictionaryService;
    private PersistenceStructureService persistenceStructureService;
    private ParameterService parameterService;
    private PermissionService permissionService;

    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "Not authorized.")
    public void handleAccessDeniedException(AccessDeniedException ex, HttpServletResponse response) {
    }

    @ExceptionHandler(NoSuchBeanDefinitionException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Data object not found.")
    public void handleNoSuchBeanDefinitionException(NoSuchBeanDefinitionException ex,
            HttpServletResponse response) {
    }

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Unexpected exception has occured.")
    public String handleRuntimeException(RuntimeException ex, HttpServletResponse response) {
        return ExceptionUtils.getStackTrace(ex);
    }

    @RequestMapping(value = "/{namespace}/{dataobject}.json", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public ResponseEntity<String> getDataObjectsAsJSON(@PathVariable("namespace") String namespace,
            @PathVariable("dataobject") String dataobject, HttpServletRequest request) throws Exception {
        FinancialSystemBusinessObjectEntry boe = getBusinessObject(dataobject);
        validateRequest(boe, namespace, dataobject, request);

        try {
            List<Map<String, String>> resultMap = generateResultMap(request, boe);

            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

            String jsonData = null;
            if (resultMap.size() == 1) {
                jsonData = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(resultMap.get(0))
                        .replaceFirst(HashMap.class.getSimpleName(), boe.getBusinessObjectClass().getName());
            } else {
                jsonData = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(resultMap).replaceFirst(
                        ArrayList.class.getSimpleName(),
                        ArrayList.class.getSimpleName() + "<" + boe.getBusinessObjectClass().getName() + ">");
            }

            return new ResponseEntity<String>(jsonData, HttpStatus.OK);
        } catch (Exception e) {
            LOG.error("Unexpected exception has occured.", e);
            throw new RuntimeException("Unexpected exception has occured.");
        }
    }

    @RequestMapping(value = "/{namespace}/{dataobject}.xml", method = RequestMethod.GET, produces = "application/xml")
    @ResponseBody
    public ResponseEntity<String> getDataObjectsAsXML(@PathVariable("namespace") String namespace,
            @PathVariable("dataobject") String dataobject, HttpServletRequest request) throws Exception {
        FinancialSystemBusinessObjectEntry boe = getBusinessObject(dataobject);
        validateRequest(boe, namespace, dataobject, request);

        try {
            List<Map<String, String>> resultMap = generateResultMap(request, boe);

            String xml = null;
            if (resultMap.size() == 1) {
                xml = RestXmlUtil.toXML(boe, resultMap.get(0));
            } else {
                xml = RestXmlUtil.toXML(boe, resultMap);
            }

            return new ResponseEntity<String>(xml, HttpStatus.OK);
        } catch (Exception e) {
            LOG.error("Unexpected exception has occured.", e);
            throw new RuntimeException("Unexpected exception has occured.");
        }
    }

    protected List<Map<String, String>> generateResultMap(HttpServletRequest request,
            FinancialSystemBusinessObjectEntry boe) {
        List<? extends BusinessObject> results = getSearchResults(request, boe);
        List<String> inquiryFields = getInquiryFields(boe);

        List<Map<String, String>> resultMap = new ArrayList<Map<String, String>>();
        for (BusinessObject bo : results) {
            Map<String, String> objectMap = new HashMap<String, String>();
            Object object = ObjectUtils.createNewObjectFromClass(boe.getBusinessObjectClass());
            for (String propertyName : inquiryFields) {
                Object propertyValue;
                try {
                    propertyValue = ObjectUtils.getPropertyValue(bo, propertyName);
                } catch (RuntimeException e) {
                    continue;
                }

                Class<?> propertyType = ObjectUtils.getPropertyType(bo, propertyName,
                        getPersistenceStructureService());
                if (isPropertyTypeValid(propertyType)) {
                    objectMap.put(propertyName, propertyValue + "");
                }
            }

            resultMap.add(objectMap);
        }

        return resultMap;
    }

    protected boolean isAuthorized(FinancialSystemBusinessObjectEntry boe) throws Exception {
        if (boe != null) {
            return getPermissionService().isAuthorizedByTemplate(GlobalVariables.getUserSession().getPrincipalId(),
                    KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.LOOK_UP_RECORDS,
                    KRADUtils.getNamespaceAndComponentSimpleName(boe.getBusinessObjectClass()),
                    Collections.<String, String>emptyMap());
        } else {
            if (boe == null) {
                LOG.warn("boe is null");
                return false;
            }
        }

        return false;
    }

    protected boolean isPropertyTypeValid(Class<?> propertyType) {
        if (propertyType != null && (TypeUtils.isStringClass(propertyType)
                || TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType)
                || TypeUtils.isTemporalClass(propertyType) || TypeUtils.isBooleanClass(propertyType))) {
            return true;
        }

        return false;
    }

    protected List<String> getInquiryFields(FinancialSystemBusinessObjectEntry boe) {
        List<String> inquiryFields = new ArrayList<String>();
        for (InquirySectionDefinition section : boe.getInquiryDefinition().getInquirySections()) {
            inquiryFields.addAll(section.getInquiryFieldNames());
        }

        return inquiryFields;
    }

    protected List<? extends BusinessObject> getSearchResults(HttpServletRequest request,
            FinancialSystemBusinessObjectEntry boe) {
        Map<String, String> fieldValues = new HashMap<String, String>();
        for (Object o : request.getParameterMap().keySet()) {
            String[] value = (String[]) request.getParameterMap().get(o);
            fieldValues.put(o.toString(), value[0]);
        }

        LookupableHelperService lookupableHelperService = getLookupableHelperService(
                boe.getLookupDefinition().getLookupableID());
        lookupableHelperService.setBusinessObjectClass(boe.getBusinessObjectClass());

        String limitByParameter = fieldValues.remove(LIMIT_BY_PARAMETER);
        String maxObjectsToReturn = fieldValues.remove(MAX_OBJECTS_TO_RETURN);

        List<? extends BusinessObject> searchResults;
        if (StringUtils.isEmpty(limitByParameter) || limitByParameter.equalsIgnoreCase("Y")) {
            searchResults = lookupableHelperService.getSearchResults(fieldValues);
        } else {
            try {
                searchResults = lookupableHelperService.getSearchResultsUnbounded(fieldValues);
            } catch (UnsupportedOperationException e) {
                LOG.warn(
                        "lookupableHelperService.getSearchResultsUnbounded failed. Retrying the lookup using the default search.",
                        e);
                searchResults = lookupableHelperService.getSearchResults(fieldValues);
            }
        }

        if (StringUtils.isNotEmpty(maxObjectsToReturn)) {
            int searchLimit = Integer.parseInt(maxObjectsToReturn);
            if (searchLimit > 0) {
                return searchResults.subList(0, Math.min(searchResults.size(), searchLimit));
            }
        }

        return searchResults;
    }

    protected void validateRequest(FinancialSystemBusinessObjectEntry boe, String namespace, String dataobject,
            HttpServletRequest request) throws Exception {
        if (boe == null) {
            LOG.debug("BusinessObjectEntry is null.");
            throw new NoSuchBeanDefinitionException("Data object not found.");
        }

        Boolean isModuleLocked = getParameterService().getParameterValueAsBoolean(namespace,
                KfsParameterConstants.PARAMETER_ALL_DETAIL_TYPE,
                KRADConstants.SystemGroupParameterNames.OLTP_LOCKOUT_ACTIVE_IND);
        boolean notAuthorized = !isAuthorized(boe);
        boolean moduleIsLocked = isModuleLocked != null && isModuleLocked;
        boolean noInquiryDefinition = !boe.hasInquiryDefinition();

        if (notAuthorized || moduleIsLocked || noInquiryDefinition) {
            LOG.debug("notAuthorized: " + notAuthorized);
            LOG.debug("moduleIsLocked: " + moduleIsLocked);
            LOG.debug("noInquiryDefinition: " + noInquiryDefinition);

            throw new AccessDeniedException("Not authorized.");
        }
    }

    protected FinancialSystemBusinessObjectEntry getBusinessObject(String dataobject) {
        try {
            return (FinancialSystemBusinessObjectEntry) getDataDictionaryService().getDictionaryObject(dataobject);
        } catch (NoSuchBeanDefinitionException e) {
            LOG.debug("Failed to retrieve data dictionary object.", e);
        }

        return null;
    }

    protected LookupableHelperService getLookupableHelperService(String lookupableID) {
        if (lookupableID != null) {
            return LookupableSpringContext.getLookupable(lookupableID).getLookupableHelperService();
        } else {
            return LookupableSpringContext.getLookupableHelperService(LOOKUPABLE_HELPER_SERVICE);
        }
    }

    public DataDictionaryService getDataDictionaryService() {
        if (this.dataDictionaryService == null) {
            this.dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
        }
        return this.dataDictionaryService;
    }

    public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
        this.dataDictionaryService = dataDictionaryService;
    }

    public PersistenceStructureService getPersistenceStructureService() {
        if (persistenceStructureService == null) {
            persistenceStructureService = KRADServiceLocator.getPersistenceStructureService();
        }
        return persistenceStructureService;
    }

    public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
        this.persistenceStructureService = persistenceStructureService;
    }

    public ParameterService getParameterService() {
        if (parameterService == null) {
            parameterService = SpringContext.getBean(ParameterService.class);
        }
        return parameterService;
    }

    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }

    public XmlObjectSerializerService getXmlObjectSerializerService() {
        return KRADServiceLocator.getXmlObjectSerializerService();
    }

    public PermissionService getPermissionService() {
        if (permissionService == null) {
            permissionService = KimApiServiceLocator.getPermissionService();
        }
        return permissionService;
    }

    public void setPermissionService(PermissionService permissionService) {
        this.permissionService = permissionService;
    }

}