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

io.soluble.pjb.bridge.http.FCGIConnectionFactory Maven / Gradle / Ivy

There is a newer version: 7.1.3
Show newest version
/*-*- mode: Java; tab-width:8 -*-*/
package io.soluble.pjb.bridge.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;
import java.util.Map;

import io.soluble.pjb.bridge.ILogger;
import io.soluble.pjb.bridge.Util;
import io.soluble.pjb.bridge.Util.Process;

/*
 * Copyright (C) 2003-2007 Jost Boekemeier
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * A factory which creates FastCGI channels.
 *
 * @author jostb
 */
public abstract class FCGIConnectionFactory {
    protected boolean promiscuous;
    protected IFCGIProcessFactory processFactory;

    /* The fast CGI Server process on this computer. Switched off per default. */
    protected IFCGIProcess proc = null;
    private boolean fcgiStarted = false;
    private final Object fcgiStartLock = new Object();
    protected Exception lastException;

    /**
     * Create a new FCGIConnectionFactory using a FCGIProcessFactory
     *
     * @param processFactory the FCGIProcessFactory
     */
    public FCGIConnectionFactory(IFCGIProcessFactory processFactory) {
        this.processFactory = processFactory;
    }

    /**
     * Start the FastCGI server
     *
     * @return false if the FastCGI server failed to start.
     */
    public final boolean startServer(ILogger logger) {
    /*
     * Try to start the FastCGI server,
	 */
        synchronized (fcgiStartLock) {
            if (!fcgiStarted) {
                if (canStartFCGI())
                    try {
                        bind(logger);
                    } catch (Exception e) {/*ignore*/}

                fcgiStarted = true; // mark as started, even if start failed
            }
        }
        return fcgiStarted;
    }

    /**
     * Test the FastCGI server.
     *
     * @throws FCGIConnectException thrown if a IOException occured.
     */
    public abstract void test() throws FCGIConnectException;

    protected abstract void waitForDaemon() throws UnknownHostException, InterruptedException;

    protected final void runFcgi(Map env, String php, boolean includeJava) {
        int c;
        byte buf[] = new byte[Util.BUF_SIZE];
        try {
            Process proc = doBind(env, php, includeJava);
            if (proc == null || proc.getInputStream() == null) return;
            /// make sure that the wrapper script launcher.sh does not output to stdout
            proc.getInputStream().close();
            // proc.OutputStream should be closed in shutdown, see PhpCGIServlet.destroy()
            InputStream in = proc.getErrorStream();
            while ((c = in.read(buf)) != -1) System.err.write(buf, 0, c);
            try {
                in.close();
            } catch (IOException e) {/*ignore*/}
        } catch (Exception e) {
            lastException = e;
            System.err.println("Could not start FCGI server: " + e);
        }
        ;
    }

    protected abstract Process doBind(Map env, String php, boolean includeJava) throws IOException;

    protected void bind(final ILogger logger) throws InterruptedException, IOException {
        Thread t = (new Util.Thread("JavaBridgeFastCGIRunner") {
            public void run() {
                Map env = (Map) processFactory.getEnvironment().clone();
                env.put("PHP_FCGI_CHILDREN", processFactory.getPhpConnectionPoolSize());
                env.put("PHP_FCGI_MAX_REQUESTS", processFactory.getPhpMaxRequests());
                runFcgi(env, processFactory.getPhp(), processFactory.getPhpIncludeJava());
            }
        });
        t.start();
        waitForDaemon();
    }

    private boolean canStartFCGI() {
        return processFactory.canStartFCGI();
    }

    public void destroy() {
        synchronized (fcgiStartLock) {
            fcgiStarted = false;
            if (proc == null) return;
            try {
                OutputStream out = proc.getOutputStream();
                if (out != null) out.close();
            } catch (IOException e) {
                Util.printStackTrace(e);
            }
            try {
                proc.waitFor();
            } catch (InterruptedException e) {
                // ignore
            }
            proc.destroy();
            proc = null;
        }
    }

    /**
     * Connect to the FastCGI server and return the connection handle.
     *
     * @return The FastCGI Channel
     * @throws FCGIConnectException thrown if a IOException occured.
     */
    public abstract FCGIConnection connect() throws FCGIConnectException;

    /**
     * For backward compatibility the "JavaBridge" context uses the port 9667 (Linux/Unix) or \\.\pipe\JavaBridge@9667 (Windogs).
     */
    public void initialize() {
        setDynamicPort();
    }

    protected abstract void setDynamicPort();

    protected abstract void setDefaultPort();

    /**
     * Return a command which may be useful for starting the FastCGI server as a separate command.
     *
     * @param base                  The context directory
     * @param php_fcgi_max_requests The number of requests, see appropriate servlet option.
     * @return A command string
     */
    public abstract String getFcgiStartCommand(String base, String php_fcgi_max_requests);

    /**
     * Find a free port or pipe name.
     *
     * @param select If select is true, the default name should be used.
     */
    public abstract void findFreePort(boolean select);

    /**
     * Create a new ChannelFactory.
     *
     * @return The concrete ChannelFactory (NP or Socket channel factory).
     */
    public static FCGIConnectionFactory createChannelFactory(IFCGIProcessFactory processFactory, boolean promiscuous) {
        if (Util.USE_SH_WRAPPER)
            return new SocketChannelFactory(processFactory, promiscuous);
        else
            return new NPChannelFactory(processFactory);
    }

    public abstract String toString();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy