org.infoscoop.web.JsonProxyServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.infoscoop.web.JsonProxyServlet.java

Source

/* infoScoop OpenSource
 * Copyright (C) 2010 Beacon IT Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation.
 * 
 * This program 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0-standalone.html>.
 */

package org.infoscoop.web;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.infoscoop.dao.OAuth2TokenDAO;
import org.infoscoop.dao.OAuthTokenDAO;
import org.infoscoop.dao.model.OAuth2Token;
import org.infoscoop.dao.model.OAuthToken;
import org.infoscoop.request.Authenticator;
import org.infoscoop.request.ProxyRequest;
import org.infoscoop.request.filter.DetectTypeFilter;
import org.infoscoop.service.OAuthService;
import org.json.JSONArray;
import org.json.JSONObject;

public class JsonProxyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private static Log log = LogFactory.getLog(JsonProxyServlet.class);

    public static enum HttpMethods {
        GET, POST, PUT, DELETE;

        public static HttpMethods as(String httpMethod) {
            for (HttpMethods value : HttpMethods.values()) {
                if (value.name().equalsIgnoreCase(httpMethod))
                    return value;
            }

            return GET;
        }

        public int invokeProxyRequest(ProxyRequest proxy) throws Exception {
            switch (this) {
            case POST:
                return proxy.executePost();
            case PUT:
                return proxy.executePut();
            case DELETE:
                return proxy.executeDelete();
            default:
                return proxy.executeGet();
            }
        }

        public HttpMethod makeMethod(String url) {
            switch (this) {
            case POST:
                return new PostMethod(url);
            case PUT:
                return new PutMethod(url);
            case DELETE:
                return new DeleteMethod(url);
            default:
                return new GetMethod(url);
            }
        }
    }

    private static enum ContentType {
        TEXT, XML, FEED("FeedJson"), JSON;

        public static ContentType as(String contentType) {
            for (ContentType value : ContentType.values()) {
                if (value.name().equalsIgnoreCase(contentType))
                    return value;
            }

            return TEXT;
        }

        private ContentType() {
            this("NoOperation");
        }

        private ContentType(String filterType) {
            this.filterType = filterType;
        }

        private String filterType;

        public String getFitlerType() {
            return filterType;
        }
    }

    private static enum AuthType {
        NONE, SIGNED, OAUTH, OAUTH2, SEND_PORTAL_UID_HEADER, POST_PORTAL_UID, BASIC;

        public static AuthType as(String authType) {
            for (AuthType value : AuthType.values()) {
                if (value.name().equalsIgnoreCase(authType))
                    return value;
            }

            return NONE;
        }
    }

    private static final String OAUTH2_FORCE_REFRESH = "OAUTH2_FORCE_REFRESH";

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    @SuppressWarnings("unchecked")
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        String uid = (String) req.getSession().getAttribute("Uid");
        Map<String, String> params = getSingleParams(req.getParameterMap());

        Map<String, List<String>> headers = new HashMap<String, List<String>>();
        for (Enumeration names = req.getHeaderNames(); names.hasMoreElements();) {
            String name = (String) names.nextElement();

            List<String> vlist = new ArrayList<String>();
            headers.put(name, vlist);
            for (Enumeration values = req.getHeaders(name); values.hasMoreElements();) {
                String value = (String) values.nextElement();
                vlist.add(value);
            }
        }

        JSONObject result;
        try {
            result = invokeJSONProxyRequest(uid, params, headers);
        } catch (Exception ex) {
            if (ex.getCause() != null)
                ex = (Exception) ex.getCause();

            log.error("", ex);

            throw new ServletException(ex);
        }

        byte[] body = ("throw 1; < don't be evil' >" + result.toString()).getBytes("UTF-8");

        resp.setStatus(200);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setContentType("text/plain;charset=UTF-8");
        //      resp.setContentType("text/plain;charset=UTF-8");
        resp.setContentLength(body.length);
        resp.getOutputStream().write(body);
        resp.getOutputStream().flush();
    }

    private Map<String, String> getSingleParams(Map<String, String[]> parameters) {
        Map<String, String> singles = new HashMap<String, String>();
        for (Map.Entry<String, String[]> p : parameters.entrySet()) {
            if (p.getValue().length > 0 && p.getValue()[0] != null && p.getValue()[0].length() > 0)
                singles.put(p.getKey(), p.getValue()[0]);
        }

        return singles;
    }

    public static JSONObject invokeJSONProxyRequest(String uid, Map<String, String> params,
            Map<String, List<String>> rheaders) throws Exception {
        AuthType authz = AuthType.as(params.get("authz"));

        HttpMethods httpMethod = HttpMethods.as(params.get("httpMethod"));
        String url = params.get("url");
        ContentType contentType = ContentType.as(params.get("contentType"));
        Map<String, String> headers = extractHeadersParam(params.get("headers"));
        String postData = params.get("postData");

        Map<String, String> filterParams = new HashMap<String, String>();
        if (contentType.equals(ContentType.FEED)) {
            filterParams.put("gs", params.get("getSummaries"));
            filterParams.put("ne", params.get("numEntries"));
        }

        JSONObject json = new JSONObject();

        JSONObject urlJson = new JSONObject();
        json.put(url, urlJson);

        String uidParamName = params.get("IS_AUTH_UID_PARAM_NAME");
        if (uidParamName != null && !"".equals(uidParamName))
            headers.put(Authenticator.UID_PARAM_NAME, uidParamName);

        ProxyRequest proxy = new ProxyRequest(url, contentType.filterType);
        proxy.setPortalUid(uid);
        String oauthServiceName = null;
        String gadgetUrl = null;
        switch (authz) {
        case OAUTH:
            headers.put("authType", "oauth");
            oauthServiceName = params.get("OAUTH_SERVICE_NAME");
            gadgetUrl = params.get("gadgetUrl");

            ProxyRequest.OAuthConfig oauthConfig = proxy.new OAuthConfig(oauthServiceName);
            oauthConfig.setRequestTokenURL(params.get("requestTokenURL"));
            oauthConfig.setRequestTokenMethod(params.get("requestTokenMethod"));
            oauthConfig.setUserAuthorizationURL(params.get("userAuthorizationURL"));
            oauthConfig.setAccessTokenURL(params.get("accessTokenURL"));
            oauthConfig.setAccessTokenMethod(params.get("accessTokenMethod"));
            oauthConfig.setGadgetUrl(gadgetUrl);
            oauthConfig.setHostPrefix(params.get("hostPrefix"));

            OAuthToken token = OAuthTokenDAO.newInstance().getAccessToken(uid, gadgetUrl, oauthServiceName);
            if (token != null) {
                oauthConfig.setAccessToken(token.getAccessToken());
                oauthConfig.setTokenSecret(token.getTokenSecret());
            }

            proxy.setOauthConfig(oauthConfig);
            break;
        case OAUTH2:
            headers.put("authType", "oauth2");
            oauthServiceName = params.get("OAUTH_SERVICE_NAME");
            gadgetUrl = params.get("gadgetUrl");

            ProxyRequest.OAuth2Config oauth2Config = proxy.new OAuth2Config(oauthServiceName);
            oauth2Config.setUserAuthorizationURL(params.get("userAuthorizationURL"));
            oauth2Config.setAccessTokenURL(params.get("accessTokenURL"));
            oauth2Config.setScope(params.get("OAUTH2_SCOPE"));
            oauth2Config.setGadgetUrl(gadgetUrl);
            oauth2Config.setHostPrefix(params.get("hostPrefix"));

            OAuth2Token token2 = OAuth2TokenDAO.newInstance().getAccessToken(uid, gadgetUrl, oauthServiceName);
            if (token2 != null) {
                oauth2Config.setCode(token2.getAuthCode());
                oauth2Config.setTokenType(token2.getTokenType());
                oauth2Config.setAccessToken(token2.getAccessToken());
                oauth2Config.setRefreshToken(token2.getRefreshToken());

                Long validityPeriodUTC = params.get(OAUTH2_FORCE_REFRESH) != null ? new Long(0)
                        : token2.getValidityPeriodUTC();

                oauth2Config.setValidityPeriodUTC(validityPeriodUTC);
            }

            proxy.setOauth2Config(oauth2Config);
            break;
        case SIGNED:
            headers.put("authType", "signed");
            headers.put("gadgetUrl", params.get("gadgetUrl"));
            headers.put("moduleId", params.get("moduleId"));
            break;
        case POST_PORTAL_UID:
            if (uid == null)
                break;

            //FIXME The postBody is overwritten by a certification information.
            headers.put("authType", "g_postPortalCredential");
            httpMethod = HttpMethods.POST;

            break;
        case SEND_PORTAL_UID_HEADER:
            if (uid == null)
                break;

            headers.put("authType", "g_sendPortalCredentialHeader");

            break;
        case BASIC:
            String username = params.get("IS_AUTH_BASIC_USERNAME");
            String password = params.get("IS_AUTH_BASIC_PASSWORD");

            headers.put("authType", "g_basic");
            headers.put("authuserid", username);
            headers.put("authpassword", password);
        }

        if (!HttpMethods.GET.equals(httpMethod) && postData != null)
            proxy.setReqeustBody(new ByteArrayInputStream(postData.getBytes("UTF-8")));

        for (Map.Entry<String, String> header : headers.entrySet())
            proxy.putRequestHeader(header.getKey(), header.getValue());

        for (Map.Entry<String, List<String>> header : rheaders.entrySet()) {
            String name = header.getKey();
            if (headers.containsKey(name))
                continue;

            for (String value : header.getValue()) {
                if (HttpMethods.GET.equals(httpMethod) && "content-length".equalsIgnoreCase(name))
                    continue;

                proxy.putRequestHeader(name, value);
            }
        }

        for (Map.Entry<String, String> filterParam : filterParams.entrySet())
            proxy.setFilterParameter(filterParam.getKey(), filterParam.getValue());

        int status = httpMethod.invokeProxyRequest(proxy);

        String bodyStr = getResponseBodyAsStringWithAutoDetect(proxy);

        urlJson.put("body", bodyStr);

        Map<String, List<String>> responseHeaders = proxy.getResponseHeaders();
        JSONObject jsonHeaders = new JSONObject();
        for (String name : responseHeaders.keySet()) {
            if (!jsonHeaders.has(name))
                jsonHeaders.put(name, new JSONArray());
            if ("oauthApprovalUrl".equalsIgnoreCase(name)) {
                urlJson.put("oauthApprovalUrl", proxy.getResponseHeader(name));
                status = 200;
            } else {
                JSONArray array = jsonHeaders.getJSONArray(name);
                List<String> values = responseHeaders.get(name);
                for (String value : values)
                    array.put(value);
            }
        }
        urlJson.put("headers", jsonHeaders);
        urlJson.put("rc", status);

        if (status == 401 && (AuthType.OAUTH == authz || AuthType.OAUTH2 == authz)) {
            if (AuthType.OAUTH == authz) {
                OAuthService.getHandle().deleteOAuthToken(uid, gadgetUrl, oauthServiceName);
            } else if (AuthType.OAUTH2 == authz) {
                ProxyRequest.OAuth2Config oauth2Config = proxy.getOauth2Config();

                // Retry if config has refreshToken only.
                if (params.get(OAUTH2_FORCE_REFRESH) == null && oauth2Config.hasRefreshToken()
                        && !oauth2Config.hasValidityPeriodUTC()) {
                    params.put(OAUTH2_FORCE_REFRESH, new String());
                    return invokeJSONProxyRequest(uid, params, rheaders);
                }

                OAuthService.getHandle().deleteOAuth2Token(uid, gadgetUrl, oauthServiceName);
            }
            log.error("OAuth request is failed:\n" + bodyStr);
            urlJson.put("oauthError", "OAuth request is failed");
        }
        return json;
    }

    public static String getResponseBodyAsStringWithAutoDetect(ProxyRequest proxy) throws Exception {
        byte[] body = ProxyRequest.stream2Bytes(proxy.getResponseBody());

        String contentType = null;
        List<String> contentTypes = proxy.getResponseHeaders("Content-Type");
        if (contentTypes.size() > 0)
            contentType = contentTypes.get(contentTypes.size() - 1);

        String encoding = DetectTypeFilter.getContentTypeCharset(contentType);
        //      if( encoding == null )
        //         encoding = DetectTypeFilter.findEncoding( new ByteArrayInputStream( body ) );
        if (encoding == null)
            encoding = "UTF-8";

        return new String(body, encoding);
    }

    public static Map<String, String> extractHeadersParam(String headerData) throws UnsupportedEncodingException {
        Map<String, String> headers = new HashMap<String, String>();
        if (headerData != null && headerData.length() > 0) {
            String[] pairs = headerData.split("&");
            for (String pair : pairs) {
                String[] header = pair.split("=");
                if (header.length != 2)
                    continue;

                headers.put(URLDecoder.decode(header[0], "UTF-8").toLowerCase(),
                        URLDecoder.decode(header[1], "UTF-8"));
            }
        }

        return headers;
    }
}