edu.mayo.cts2.framework.webapp.rest.controller.AbstractController.java Source code

Java tutorial

Introduction

Here is the source code for edu.mayo.cts2.framework.webapp.rest.controller.AbstractController.java

Source

/*
 * Copyright: (c) 2004-2011 Mayo Foundation for Medical Education and 
 * Research (MFMER). All rights reserved. MAYO, MAYO CLINIC, and the
 * triple-shield Mayo logo are trademarks and service marks of MFMER.
 *
 * Except as contained in the copyright notice above, or as used to identify 
 * MFMER as the author of this software, the trade names, trademarks, service
 * marks, or product names of the copyright holder shall not be used in
 * advertising, promotion or otherwise in connection with this software without
 * prior written authorization of the copyright holder.
 *
 * 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.
 */
package edu.mayo.cts2.framework.webapp.rest.controller;

import edu.mayo.cts2.framework.core.constants.ModelAndViewInterface;
import edu.mayo.cts2.framework.core.constants.URIHelperInterface;
import edu.mayo.cts2.framework.core.util.EncodingUtils;
import edu.mayo.cts2.framework.model.command.Page;
import edu.mayo.cts2.framework.model.core.ScopedEntityName;
import edu.mayo.cts2.framework.model.core.URIAndEntityName;
import edu.mayo.cts2.framework.model.exception.ExceptionFactory;
import edu.mayo.cts2.framework.model.exception.UnspecifiedCts2Exception;
import edu.mayo.cts2.framework.model.service.core.types.LoggingLevel;
import edu.mayo.cts2.framework.model.service.exception.CTS2Exception;
import edu.mayo.cts2.framework.webapp.rest.command.RestFilter;
import edu.mayo.cts2.framework.webapp.rest.command.RestFilters;
import edu.mayo.cts2.framework.webapp.rest.config.RestConfig;
import edu.mayo.cts2.framework.webapp.rest.exception.Cts2RestExceptionCodeMapper;
import edu.mayo.cts2.framework.webapp.rest.exception.StatusSettingCts2RestException;
import edu.mayo.cts2.framework.webapp.service.AbstractServiceAwareBean;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UrlPathHelper;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * The base abstract Spring MVC Controller.
 *
 * @author <a href="mailto:kevin.peterson@mayo.edu">Kevin Peterson</a>
 */
public abstract class AbstractController extends AbstractServiceAwareBean
        implements URIHelperInterface, ModelAndViewInterface {

    protected Log log = LogFactory.getLog(getClass());

    protected static final String DEFAULT_REDIRECT = "true";

    @Resource
    private RestConfig restConfig;

    @Resource
    private Cts2RestExceptionCodeMapper cts2RestExceptionCodeMapper;

    private UrlPathHelper urlPathHelper = new UrlPathHelper();

    /**
     * Decode uri.
     *
     * @param uri the uri
     * @return the string
     */
    protected String decodeUri(String uri) {
        try {
            return URLDecoder.decode(uri, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Handle exception.
     *
     * @param response the response
     * @param ex the ex
     * @return the model and view
     */
    @ExceptionHandler(CTS2Exception.class)
    @ResponseBody
    public CTS2Exception handleException(HttpServletRequest request, HttpServletResponse response,
            CTS2Exception ex) {
        int status = this.cts2RestExceptionCodeMapper.getErrorCode(ex);

        try {
            //Horrible hack for Firefox - https://github.com/cts2/cts2-framework/issues/30 - https://bugzilla.mozilla.org/show_bug.cgi?id=907800
            if (status == 408 && request.getHeader("User-Agent").indexOf("Firefox") > 0) {
                status = 508;
            }
        } catch (Exception e) {
            // noop - just want to ensure this hack doesn't break other things unexpectedly
        }

        if (ex.getSeverity() == null) {
            ex.setSeverity(LoggingLevel.ERROR);
        }

        response.setStatus(status);

        return ex;
    }

    @ExceptionHandler(StatusSettingCts2RestException.class)
    @ResponseBody
    public CTS2Exception handleException(HttpServletResponse response, StatusSettingCts2RestException ex) {
        response.setStatus(ex.getStatusCode());

        return ex;
    }

    /**
     * Handle exception.
     *
     * @param response the response
     * @param request the request
     * @param ex the ex
     * @return the model and view
     */
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public CTS2Exception handleException(HttpServletResponse response, HttpServletRequest request,
            RuntimeException ex) {
        String errorId = Long.toString(new Date().getTime());

        log.error("Unexpected Error: " + errorId, ex);

        int status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;

        response.setStatus(status);

        boolean showStackTrace = this.getRestConfig().getShowStackTraceOnError();

        if (showStackTrace) {
            return ExceptionFactory.createUnknownException(ex, getUrlString(request), getParameterString(request),
                    true);
        } else {
            return ExceptionFactory.createUnknownException(this.getErrorSupportMessage(errorId),
                    getUrlString(request), getParameterString(request));
        }
    }

    protected String getErrorSupportMessage(String errorId) {
        String preamble = "An Unexpected error has occurred.";

        String supportEmail = this.getRestConfig().getSupportEmail();

        if (StringUtils.isNotBlank(supportEmail)) {
            preamble = preamble + "\nPlease contact " + supportEmail + " and reference Log ID: " + errorId;
        }

        return preamble;
    }

    /**
     * Handle exception.
     *
     * @param response the response
     * @param request the request
     * @param ex the ex
     * @return the model and view
     */
    @ExceptionHandler(UnsupportedOperationException.class)
    @ResponseBody
    public CTS2Exception handleException(HttpServletResponse response, HttpServletRequest request,
            UnsupportedOperationException ex) {
        int status = HttpServletResponse.SC_NOT_IMPLEMENTED;

        response.setStatus(status);

        return ExceptionFactory.createUnknownException(
                "Method not implemented. " + ex.getMessage() != null ? ex.getMessage() : "", getUrlString(request),
                getParameterString(request));
    }

    /**
     * Gets the url string.
     *
     * @param request the request
     * @return the url string
     */
    private String getUrlString(HttpServletRequest request) {
        return request.getContextPath();
    }

    /**
     * Gets the parameter string.
     *
     * @param request the request
     * @return the parameter string
     */
    private String getParameterString(HttpServletRequest request) {
        return request.getQueryString();
    }

    /**
     * Sets the count.
     *
     * @param count the count
     * @param httpServletResponse the http servlet response
     */
    protected void setCount(int count, HttpServletResponse httpServletResponse) {
        httpServletResponse.setHeader(HEADER_COUNT, Integer.toString(count));
    }

    protected boolean isPartialRedirect(HttpServletRequest request, String urlTemplatePath) {
        String adjustedTemplate = StringUtils.removeEnd(urlTemplatePath, ALL_WILDCARD);

        String contextPath = this.getUrlPathHelper().getContextPath(request);

        String requestUri = StringUtils.removeStart(request.getRequestURI(), contextPath);

        return !(StringUtils.removeStart(StringUtils.removeEnd(requestUri, "/"), "/")
                .equals(StringUtils.removeStart(StringUtils.removeEnd(adjustedTemplate, "/"), "/")));
    }

    @ExceptionHandler(ConversionNotSupportedException.class)
    @ResponseBody
    public UnspecifiedCts2Exception handleException(HttpServletResponse response, HttpServletRequest request,
            ConversionNotSupportedException ex) {
        int status = HttpServletResponse.SC_BAD_REQUEST;
        response.setStatus(status);

        Class<?> requiredType = ex.getRequiredType();
        String typeName = requiredType.getSimpleName();
        String value = ex.getValue().toString();

        String possibleValues = "";

        if (requiredType.isEnum()) {
            StringBuilder sb = new StringBuilder();
            sb.append(" Possible values include: ");

            Object[] values = requiredType.getEnumConstants();

            sb.append(StringUtils.join(values, ", "));

            possibleValues = sb.toString();
        }

        return ExceptionFactory.createUnknownException(
                "Cannot convert value " + value + " to the type " + typeName + "." + possibleValues,
                getUrlString(request), getParameterString(request));
    }

    /**
     * Gets the end.
     *
     * @param page the page
     * @return the end
     */
    protected int getEnd(Page page) {
        return (page.getPage() + 1) * page.getMaxToReturn();
    }

    /**
     * Checks if is last page.
     *
     * @param page the page
     * @param pageSize the page size
     * @return true, if is last page
     */
    protected boolean isLastPage(Page page, int pageSize) {
        return pageSize < page.getMaxToReturn();
    }

    /**
     * Gets the start.
     *
     * @param page the page
     * @return the start
     */
    protected int getStart(Page page) {
        return page.getPage() * page.getMaxToReturn();
    }

    @InitBinder
    public void initPageBinder(WebDataBinder binder,
            @RequestParam(value = PARAM_MAXTORETURN, required = false) Integer maxToReturn,
            @RequestParam(value = PARAM_PAGE, required = false) Integer pageNumber) {

        if (binder.getTarget() instanceof Page) {
            Page page = (Page) binder.getTarget();

            if (maxToReturn != null) {
                page.setMaxToReturn(maxToReturn);
            } else {
                // get default page size if it is not null in the properties file
                if (getRestConfig().getMaxToReturn() != null) {
                    page.setMaxToReturn(getRestConfig().getMaxToReturn().intValue());
                }
            }

            if (pageNumber != null) {
                page.setPage(pageNumber);
            }

        }
    }

    @InitBinder
    public void initEntityDescriptionRestrictionBinder(WebDataBinder binder,
            @RequestParam(value = PARAM_FILTERCOMPONENT, required = false) String filterComponent,
            @RequestParam(value = PARAM_MATCHALGORITHM, required = false) String matchAlgorithm,
            @RequestParam(value = PARAM_MATCHVALUE, required = false) String matchValue) {

        if (binder.getTarget() instanceof RestFilters) {
            RestFilters filters = (RestFilters) binder.getTarget();

            if (StringUtils.isNotBlank(matchValue)) {
                RestFilter filter = new RestFilter();
                if (StringUtils.isNotBlank(filterComponent)) {
                    filter.setFiltercomponent(filterComponent);
                }
                if (StringUtils.isNotBlank(matchAlgorithm)) {
                    filter.setMatchalgorithm(matchAlgorithm);
                }
                filter.setMatchvalue(matchValue);

                filters.getRestFilters().add(filter);
            }
        }
    }

    /**
     * Gets the scoped entity name.
     *
     * @param entityName the entity name
     * @param codeSystemName the code system name
     * @return the scoped entity name
     */
    protected ScopedEntityName getScopedEntityName(String entityName, String codeSystemName) {
        return EncodingUtils.decodeEntityName(entityName, codeSystemName);
    }

    protected <T> Set<T> createSet(T element) {
        Set<T> set = new HashSet<T>();
        set.add(element);
        return set;
    }

    protected ScopedEntityName getScopedEntityName(String encodedEntityName) {
        return EncodingUtils.decodeEntityName(encodedEntityName);
    }

    protected String getScopedEntityName(ScopedEntityName scopedEntityName) {
        return EncodingUtils.encodeScopedEntityName(scopedEntityName);
    }

    protected String getScopedEntityName(URIAndEntityName uriAndEntityName) {
        return EncodingUtils.encodeScopedEntityName(uriAndEntityName);
    }

    protected UrlPathHelper getUrlPathHelper() {
        return urlPathHelper;
    }

    protected RestConfig getRestConfig() {
        return restConfig;
    }

    protected void setRestConfig(RestConfig restConfig) {
        this.restConfig = restConfig;
    }
}