nl.strohalm.cyclos.http.RestFilter.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.http.RestFilter.java

Source

/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
    
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
    
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 */
package nl.strohalm.cyclos.http;

import java.io.IOException;
import java.util.Properties;

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

import nl.strohalm.cyclos.annotations.Inject;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.services.application.ApplicationService;
import nl.strohalm.cyclos.utils.Pair;
import nl.strohalm.cyclos.utils.access.LoggedUser;
import nl.strohalm.cyclos.utils.logging.LoggingHandler;
import nl.strohalm.cyclos.utils.logging.RestLogDTO;
import nl.strohalm.cyclos.webservices.WebServiceContext;
import nl.strohalm.cyclos.webservices.model.ServerErrorVO;
import nl.strohalm.cyclos.webservices.rest.RestHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.simple.JSONObject;
import org.springframework.http.HttpStatus;

/**
 * Filter which handles the REST services context
 * @author luis
 */
public class RestFilter extends BaseWebServiceTransactionFilter {

    private static final Log LOG = LogFactory.getLog(RestFilter.class);
    private ApplicationService applicationService;
    private LoggingHandler loggingHandler;
    private boolean restDisabled;

    @Inject
    public void setApplicationService(final ApplicationService applicationService) {
        this.applicationService = applicationService;
    }

    @Inject
    public void setCyclosProperties(final Properties properties) {
        final String disabled = properties.getProperty("cyclos.disableRestServices", "false");
        restDisabled = Boolean.parseBoolean(disabled);
    }

    @Inject
    public void setLoggingHandler(final LoggingHandler loggingHandler) {
        this.loggingHandler = loggingHandler;
    }

    @Override
    protected boolean applyResponseStateOnRollback() {
        return false;
    }

    @Override
    protected void execute(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) throws IOException, ServletException {
        // If Rest is disabled by configuration, always send a 404 error
        if (restDisabled) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // Check if the application is online
        if (!applicationService.isOnline()) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
            return;
        }

        // Add no cache control
        response.setHeader("Cache-control", "no-cache, no-store, must-revalidate");

        // Check non-secure access when HTTP is enabled
        if (Boolean.TRUE.equals(getServletContext().getAttribute("cyclos.httpEnabled"))) {
            if (!"https".equalsIgnoreCase(request.getProtocol())) {
                response.sendError(HttpStatus.UPGRADE_REQUIRED.value(),
                        HttpStatus.UPGRADE_REQUIRED.getReasonPhrase());
                response.addHeader("Upgrade", "TLS/1.0, HTTP/1.1");
                response.addHeader("Connection", "Upgrade");
                return;
            }
        }

        // When logging REST parameters, we need to wrap the request with StringBodyRequest in order to have the body available
        final boolean logParameters = loggingHandler.isRestParametersLogEnabled();
        super.execute(logParameters ? new StringBodyRequest(request) : request, response, chain);
    }

    @Override
    protected Log getLog() {
        return LOG;
    }

    @Override
    protected String getServiceName() {
        return "REST web service";
    }

    @Override
    protected boolean handleSilencedErrors() {
        return true;
    }

    @Override
    protected void onBeforeRunInTransaction(final HttpServletRequest request, final HttpServletResponse response) {
        WebServiceContext.set((Member) null, getServletContext(), request, response);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void onError(final HttpServletRequest request, final HttpServletResponse response, final Throwable t)
            throws IOException {
        log(request, t);
        LOG.error("Error on REST call", t);
        final Pair<ServerErrorVO, Integer> error = RestHelper.resolveError(t);
        final ServerErrorVO vo = error.getFirst();
        final JSONObject json = new JSONObject();
        if (StringUtils.isNotEmpty(vo.getErrorCode())) {
            json.put("errorCode", vo.getErrorCode());
        }
        if (StringUtils.isNotEmpty(vo.getErrorDetails())) {
            json.put("errorDetails", vo.getErrorDetails());
        }
        response.setStatus(error.getSecond());
        response.setContentType("application/json");
        json.writeJSONString(response.getWriter());
        response.flushBuffer();
    }

    @Override
    protected void onTransactionEnd(final HttpServletRequest request, final HttpServletResponse response) {
        // Generate the trace log
        log(request, null);
    }

    private RestLogDTO buildLogDTO(final HttpServletRequest request, final Throwable error) {
        String body;
        if (request instanceof StringBodyRequest) {
            try {
                body = ((StringBodyRequest) request).getBody();
            } catch (final Exception e) {
                body = "<Error obtaining request body: " + e.toString() + ">";
            }
        } else {
            body = null;
        }

        final RestLogDTO dto = new RestLogDTO();
        dto.setRemoteAddress(request.getRemoteAddr());
        dto.setMember(LoggedUser.hasUser() ? LoggedUser.member() : null);
        dto.setMethod(request.getMethod());
        dto.setUri(request.getRequestURI());
        dto.setQueryString(request.getQueryString());
        dto.setRequestBody(body);
        return dto;
    }

    private void log(final HttpServletRequest request, final Throwable error) {
        final RestLogDTO dto = buildLogDTO(request, error);
        loggingHandler.traceRest(dto);
    }
}