All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.scripting.jython.grizzly.WSGIGrizzlyAdapter Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
/*
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.scripting.jython.grizzly;

import com.sun.grizzly.tcp.http11.GrizzlyAdapter;
import com.sun.grizzly.tcp.http11.GrizzlyRequest;
import com.sun.grizzly.tcp.http11.GrizzlyResponse;
import org.python.core.PyDictionary;
import org.python.core.PyObject;
import org.python.core.PyString;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

public class WSGIGrizzlyAdapter extends GrizzlyAdapter {
    JythonApp myApp; //This will have to change when we want to support a non-threadsafe framework. Right now, I want to avoid the extra layer of wrapping.
    JythonLogger theLog;
    JyConfig myConfig;

    // Cached environment objects
    private final PyObject version;
    private final PyObject versionKey;
    private final PyObject errorStream;
    private final PyObject errorStreamKey;
    private final PyObject scriptName;
    private final PyObject scriptNameKey;
    private final PyObject pyTrue;
    private final PyObject pyFalse;
    private final PyObject multithread;
    private final PyObject multiprocess;
    private final PyObject run_once;

    // Probably need a constructor here...
    public WSGIGrizzlyAdapter(JyConfig config) {
        super(config.getAppPath());
        myConfig = config;
        //this.setHandleStaticResources(false);
        //this.setRootFolder(config.getAppPath() + File.separator+"public");
        theLog = JythonLogger.getOrCreateInstance(config.getLogger());
        // I'm a bit unclear on how this should work. The factory wants the path to the Jython module.
        // The Jython module is in org.glassfish.scripting.jython (right now), but will be somewhere in the same jar we are in
        // Thus, it should be on the classpath and such, but the full path will vary (depending on where GF is installed and such
        // Right now, I'm hoping that relative pathing will solve my problems, but I'm not sure. Is there a better/correct way to do that?
        String pathToJythonModule = JythonApplicationChooser.detect(config.getAppType());
        myApp = (JythonApp)JythonFactory.getJythonObject("org.glassfish.scripting.jython.grizzly.JythonApp", pathToJythonModule, myConfig);
        if (!(myApp.start(myConfig))) {
            // startup failed, complain about it
            theLog.getLogger().severe("WSGIGrizzlyAdapter cancels Start: Interrupted by Jython Application startup failure");
            throw new IllegalStateException("Jython Application at " + config.getAppPath() + " did not start");
        } // Otherwise, everything is fine

        // Set up environment caching
        List v = new LinkedList();
        v.add(1);
        v.add(0);
        version = makePy(v);
        versionKey = makePy("wsgi.version");
        errorStream = makePy(theLog);
        errorStreamKey = makePy("wsgi.errors");
        scriptName = makePy(config.getContextRoot());
        scriptNameKey = makePy("SCRIPT_NAME");
        pyTrue = makePy(true);
        pyFalse = makePy(false);
        multithread = makePy("wsgi.multithread");
        multiprocess = makePy("wsgi.multiprocess");
        run_once = makePy("wsgi.run_once");
        // If a media root is provided, use it.
        if (config.getMediaRoot() != null && !(config.getMediaRoot().equals(""))) {
            this.setHandleStaticResources(true);
            this.setRootFolder(config.getMediaRoot());
        } else {
            this.setHandleStaticResources(false);
        }

    }

    public void service(GrizzlyRequest grizzlyRequest, GrizzlyResponse grizzlyResponse) {
        // Construct the dictionary
        PyDictionary environment = makeEnvironment(grizzlyRequest);
        Response r = WSGIResponse.create(grizzlyResponse);
        PyObject response = myApp.call(environment, r);
        PyObject iter = response.__iter__();
        try {
            for (PyObject line : iter.asIterable()) {
                grizzlyResponse.getWriter().write(line.toString());
            }
        }
        catch (IOException e) {
            theLog.getLogger().severe("WSGIGrizzlyAdapter cancels Service Request: Interrupted by IO exception");

        } finally {
            // We really should call a "close" method in here, if the iterable has one. But, we can't tell =(
            myApp.finish();
        }
    }

    private PyDictionary makeEnvironment(GrizzlyRequest req) {
        PyDictionary env = new PyDictionary();
        // Required WSGI variables, from http://www.python.org/dev/peps/pep-0333/
        env.__setitem__(versionKey, version);
        addPyString(env, "wsgi.url_scheme", req.getScheme());
        try {
            addPyObjects(env, "wsgi.input", WSGIGrizzlyWrapper.wrap(req.getInputStream()));
        } catch (IOException e) {
               theLog.getLogger().severe("WSGIGrizzlyAdapter cancels Construct Dictionary: Interruped by IO exception getting input stream");
        }
        env.__setitem__(errorStreamKey, errorStream);
        env.__setitem__(multithread, pyTrue);
        env.__setitem__(multiprocess, pyFalse);
        env.__setitem__(run_once, pyFalse);

        // required CGI variables
        addPyString(env, "REQUEST_METHOD", req.getMethod());
        env.__setitem__(scriptNameKey, scriptName);
        env.__setitem__(new PyString("django.root"), scriptName);
        String response = req.getRequestURI();
        if (!myConfig.getContextRoot().equals("/")) { // Don't trim if we're at the root
            response = response.replaceFirst(myConfig.getContextRoot(), "");
        }
        addPyString(env, "PATH_INFO", response);
        addPyString(env, "QUERY_STRING", (req.getQueryString() == null)?req.getQueryString():"");
        addPyString(env, "CONTENT_TYPE", req.getHeader("Content-Type"));
        addPyString(env, "CONTENT_LENGTH", req.getHeader("Content-Length"));
        addPyString(env, "SERVER_NAME", req.getServerName());
        addPyString(env, "SERVER_PORT", Integer.toString(req.getServerPort()));
        addPyString(env, "SERVER_PROTOCOL", req.getProtocol());

        //HTTP_ headers
        Enumeration headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String next = headerNames.nextElement();
            //if (next.startsWith("HTTP_")) {
            String header = req.getHeader(next).replaceAll("-","_");
            next = next.replaceAll("-","_").toUpperCase();
                addPyString(env, "HTTP_" + next, header);
            //}
        }
        return env;

    }
    private PyObject makePy (Object o) {
        return org.python.core.Py.java2py(o);
    }

    private void addPyObjects(PyDictionary dict, Object key, Object value) {
        dict.__setitem__(makePy(key), makePy(value));
    }
    private void addPyString(PyDictionary dict, String key, String value) {
        if (key == null) {
            key = "";
        }
        if (value == null) {
            value = "";
        }
        dict.__setitem__(new PyString(key), new PyString(value));
    }

    /**
     * Called from {@link org.glassfish.scripting.jython.grizzly.JythonRuntime#stopJythonRuntimePool()} when Jython app
     * is undeployed.
     */
    /*package*/ void stopJythonRuntimePool(){
        //TODO: Fill in the code when Jython runtime pool is implemented.    
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy