com.predic8.membrane.servlet.embedded.RStudioMembraneServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.predic8.membrane.servlet.embedded.RStudioMembraneServlet.java

Source

/*
 * This file is part of Hopsworks
 * Copyright (C) 2018, Logical Clocks AB. All rights reserved
    
 * Hopsworks is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Hopsworks 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package com.predic8.membrane.servlet.embedded;

import java.io.IOException;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.predic8.membrane.core.Router;
import com.predic8.membrane.core.RuleManager;
import com.predic8.membrane.core.rules.ProxyRule;
import com.predic8.membrane.core.rules.ProxyRuleKey;
import com.predic8.membrane.core.rules.ServiceProxy;
import com.predic8.membrane.core.rules.ServiceProxyKey;
import io.hops.hopsworks.common.util.Ip;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;

/**
 * This embeds Membrane as a servlet.
 */
@SuppressWarnings({ "serial" })
public class RStudioMembraneServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private static final Log logger = LogFactory.getLog(RStudioMembraneServlet.class);

    @Override
    public void init(ServletConfig config) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String queryString = req.getQueryString() == null ? "" : "?" + req.getQueryString();

        Router router;

        // For websockets, the following paths are used by JupyterHub:
        //  /(user/[^/]*)/(api/kernels/[^/]+/channels|terminals/websocket)/?
        // forward to ws(s)://servername:port_number
        //<LocationMatch "/mypath/(user/[^/]*)/(api/kernels/[^/]+/channels|terminals/websocket)(.*)">
        //    ProxyPassMatch ws://localhost:8999/mypath/$1/$2$3
        //    ProxyPassReverse ws://localhost:8999 # this may be superfluous
        //</LocationMatch>
        //        ProxyPass /api/kernels/ ws://192.168.254.23:8888/api/kernels/
        //        ProxyPassReverse /api/kernels/ http://192.168.254.23:8888/api/kernels/
        List<NameValuePair> pairs;
        try {
            //note: HttpClient 4.2 lets you parse the string without building the URI
            pairs = URLEncodedUtils.parse(new URI(queryString), "UTF-8");
        } catch (URISyntaxException e) {
            throw new ServletException("Unexpected URI parsing error on " + queryString, e);
        }
        LinkedHashMap<String, String> params = new LinkedHashMap<>();
        for (NameValuePair pair : pairs) {
            params.put(pair.getName(), pair.getValue());
        }

        String externalIp = Ip.getHost(req.getRequestURL().toString());

        StringBuffer urlBuf = new StringBuffer("http://localhost:");

        String ctxPath = req.getRequestURI();

        int x = ctxPath.indexOf("/rstudio");
        int firstSlash = ctxPath.indexOf('/', x + 1);
        int secondSlash = ctxPath.indexOf('/', firstSlash + 1);
        String portString = ctxPath.substring(firstSlash + 1, secondSlash);
        Integer targetPort;
        try {
            targetPort = Integer.parseInt(portString);
        } catch (NumberFormatException ex) {
            logger.error("Invalid target port in the URL: " + portString);
            return;
        }
        urlBuf.append(portString);

        String newTargetUri = urlBuf.toString() + req.getRequestURI();

        StringBuilder newQueryBuf = new StringBuilder();
        newQueryBuf.append(newTargetUri);
        newQueryBuf.append(queryString);

        URI targetUriObj = null;
        try {
            targetUriObj = new URI(newQueryBuf.toString());
        } catch (Exception e) {
            throw new ServletException("Rewritten targetUri is invalid: " + newTargetUri, e);
        }
        ServiceProxy sp = new ServiceProxy(new ServiceProxyKey(externalIp, "*", "*", -1), "localhost", targetPort);
        //    ServiceProxy sp = new ServiceProxy(
        //            new ServiceProxyKey(
        //                    externalIp, "*", "*", -1),
        //            "localhost", targetPort);
        sp.setTargetURL(newQueryBuf.toString());
        // only set external hostname in case admin console is used
        try {
            router = new HopsRouter(targetUriObj);
            router.add(sp);
            router.init();
            ProxyRule proxy = new ProxyRule(new ProxyRuleKey(-1));
            router.getRuleManager().addProxy(proxy, RuleManager.RuleDefinitionSource.MANUAL);
            router.getRuleManager().addProxy(sp, RuleManager.RuleDefinitionSource.MANUAL);
            new HopsServletHandler(req, resp, router.getTransport(), targetUriObj).run();
        } catch (Exception ex) {
            Logger.getLogger(RStudioMembraneServlet.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

}