org.ofbiz.base.start.Start.java Source code

Java tutorial

Introduction

Here is the source code for org.ofbiz.base.start.Start.java

Source

/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *******************************************************************************/
package org.ofbiz.base.start;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Start - OFBiz Container(s) Startup Class
 *
 */
public class Start {

    private enum Control {
        SHUTDOWN {
            void processRequest(Start start, PrintWriter writer) {
                if (start.serverState.get() == ServerState.STOPPING) {
                    writer.println("IN-PROGRESS");
                } else {
                    writer.println("OK");
                    writer.flush();
                    start.stopServer();
                }
            }
        },
        STATUS {
            void processRequest(Start start, PrintWriter writer) {
                writer.println(start.serverState.get());
            }
        },
        FAIL {
            void processRequest(Start start, PrintWriter writer) {
                writer.println("FAIL");
            }
        };

        abstract void processRequest(Start start, PrintWriter writer);
    }

    private static void help(PrintStream out) {
        out.println("");
        out.println("Usage: java -jar ofbiz.jar [command] [arguments]");
        out.println("-both    -----> Run simultaneously the POS (Point of Sales) application and OFBiz standard");
        out.println("-help, -? ----> This screen");
        out.println("-install -----> Run install (create tables/load data)");
        out.println("-pos     -----> Run the POS (Point of Sales) application");
        out.println("-setup -------> Run external application server setup");
        out.println("-start -------> Start the server");
        out.println("-status ------> Status of the server");
        out.println("-shutdown ----> Shutdown the server");
        out.println("-test --------> Run the JUnit test script");
        out.println("[no config] --> Use default config");
        out.println("[no command] -> Start the server w/ default config");
    }

    private enum Command {
        HELP, HELP_ERROR, STATUS, SHUTDOWN, COMMAND
    }

    private static Command checkCommand(Command command, Command wanted) {
        if (wanted == Command.HELP || wanted.equals(command)) {
            return wanted;
        } else if (command == null) {
            return wanted;
        } else {
            System.err.println("Duplicate command detected(was " + command + ", wanted " + wanted);
            return Command.HELP_ERROR;
        }
    }

    public static void main(String[] args) throws StartupException {
        Command command = null;
        List<String> loaderArgs = new ArrayList<String>(args.length);
        for (String arg : args) {
            if (arg.equals("-help") || arg.equals("-?")) {
                command = checkCommand(command, Command.HELP);
            } else if (arg.equals("-status")) {
                command = checkCommand(command, Command.STATUS);
            } else if (arg.equals("-shutdown")) {
                command = checkCommand(command, Command.SHUTDOWN);
            } else if (arg.startsWith("-")) {
                command = checkCommand(command, Command.COMMAND);
                loaderArgs.add(arg.substring(1));
            } else {
                command = checkCommand(command, Command.COMMAND);
                if (command == Command.COMMAND) {
                    loaderArgs.add(arg);
                } else {
                    command = Command.HELP_ERROR;
                }
            }
        }
        if (command == null) {
            command = Command.COMMAND;
            loaderArgs.add("start");
        }
        if (command == Command.HELP) {
            help(System.out);
            return;
        } else if (command == Command.HELP_ERROR) {
            help(System.err);
            System.exit(1);
        }
        Start start = new Start();
        start.init(args, command == Command.COMMAND);
        try {
            if (command == Command.STATUS) {
                System.out.println("Current Status : " + start.status());
            } else if (command == Command.SHUTDOWN) {
                System.out.println("Shutting down server : " + start.shutdown());
            } else {
                // general start
                start.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(99);
        }
    }

    private enum ServerState {
        STARTING, RUNNING, STOPPING;

        public String toString() {
            return name().charAt(0) + name().substring(1).toLowerCase();
        }
    }

    private Config config = null;
    private List<String> loaderArgs = new ArrayList<String>();
    private final ArrayList<StartupLoader> loaders = new ArrayList<StartupLoader>();
    private AtomicReference<ServerState> serverState = new AtomicReference<ServerState>(ServerState.STARTING);
    private Thread adminPortThread = null;

    private void createListenerThread() throws StartupException {
        if (config.adminPort > 0) {
            this.adminPortThread = new AdminPortThread();
            this.adminPortThread.start();
        } else {
            System.out.println("Admin socket not configured; set to port 0");
        }
    }

    private void createLogDirectory() {
        File logDir = new File(config.logDir);
        if (!logDir.exists()) {
            if (logDir.mkdir()) {
                System.out.println("Created OFBiz log dir [" + logDir.getAbsolutePath() + "]");
            }
        }
    }

    public void init(String[] args) throws StartupException {
        init(args, true);
    }

    public void init(String[] args, boolean fullInit) throws StartupException {
        String globalSystemPropsFileName = System.getProperty("ofbiz.system.props");
        if (globalSystemPropsFileName != null) {
            FileInputStream stream = null;
            try {
                stream = new FileInputStream(globalSystemPropsFileName);
                System.getProperties().load(stream);
            } catch (IOException e) {
                throw (StartupException) new StartupException("Couldn't load global system props").initCause(e);
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        throw (StartupException) new StartupException("Couldn't close stream").initCause(e);
                    }
                }
            }
        }
        try {
            this.config = Config.getInstance(args);
        } catch (IOException e) {
            throw (StartupException) new StartupException("Couldn't not fetch config instance").initCause(e);
        }
        // parse the startup arguments
        if (args.length > 1) {
            this.loaderArgs.addAll(Arrays.asList(args).subList(1, args.length));
        }

        if (!fullInit) {
            return;
        }
        // initialize the classpath
        initClasspath();

        // create the log directory
        createLogDirectory();

        // create the listener thread
        createListenerThread();

        // set the shutdown hook
        if (config.useShutdownHook) {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    shutdownServer();
                }
            });
        } else {
            System.out.println("Shutdown hook disabled");
        }

        // initialize the startup loaders
        initStartLoaders();
    }

    private void initClasspath() throws StartupException {
        Classpath classPath = new Classpath(System.getProperty("java.class.path"));
        try {
            this.config.initClasspath(classPath);
        } catch (IOException e) {
            throw (StartupException) new StartupException("Couldn't initialized classpath").initCause(e);
        }
        // Set the classpath/classloader
        System.setProperty("java.class.path", classPath.toString());
        ClassLoader classloader = classPath.getClassLoader();
        Thread.currentThread().setContextClassLoader(classloader);
        if (System.getProperty("DEBUG") != null) {
            System.out.println("Startup Classloader: " + classloader.toString());
            System.out.println("Startup Classpath: " + classPath.toString());
        }
    }

    private void initStartLoaders() throws StartupException {
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        synchronized (this.loaders) {
            // initialize the loaders
            for (String loaderClassName : config.loaders) {
                if (this.serverState.get() == ServerState.STOPPING) {
                    return;
                }
                try {
                    Class<?> loaderClass = classloader.loadClass(loaderClassName);
                    StartupLoader loader = (StartupLoader) loaderClass.newInstance();
                    loader.load(config, loaderArgs.toArray(new String[loaderArgs.size()]));
                    loaders.add(loader);
                } catch (ClassNotFoundException e) {
                    throw (StartupException) new StartupException(e.getMessage()).initCause(e);
                } catch (InstantiationException e) {
                    throw (StartupException) new StartupException(e.getMessage()).initCause(e);
                } catch (IllegalAccessException e) {
                    throw (StartupException) new StartupException(e.getMessage()).initCause(e);
                }
            }
            this.loaders.trimToSize();
        }
        return;
    }

    private String sendSocketCommand(Control control) throws IOException, ConnectException {
        String response = "OFBiz is Down";

        try {
            Socket socket = new Socket(config.adminAddress, config.adminPort);

            // send the command
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            writer.println(config.adminKey + ":" + control);
            writer.flush();

            // read the reply
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            response = reader.readLine();

            reader.close();

            // close the socket
            writer.close();
            socket.close();

        } catch (ConnectException e) {
            System.out.println("Could not connect to " + config.adminAddress + ":" + config.adminPort);
        }
        return response;
    }

    public String shutdown() throws IOException {
        return sendSocketCommand(Control.SHUTDOWN);
    }

    private void shutdownServer() {
        ServerState currentState;
        do {
            currentState = this.serverState.get();
            if (currentState == ServerState.STOPPING) {
                return;
            }
        } while (!this.serverState.compareAndSet(currentState, ServerState.STOPPING));
        // The current thread was the one that successfully changed the state;
        // continue with further processing.
        synchronized (this.loaders) {
            // Unload in reverse order
            for (int i = this.loaders.size(); i > 0; i--) {
                StartupLoader loader = this.loaders.get(i - 1);
                try {
                    loader.unload();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        if (this.adminPortThread != null && this.adminPortThread.isAlive()) {
            this.adminPortThread.interrupt();
        }
    }

    // org.apache.commons.daemon.Daemon.start()
    public void start() throws Exception {
        if (!startStartLoaders()) {
            if (this.serverState.get() == ServerState.STOPPING) {
                return;
            } else {
                throw new Exception("Error during start.");
            }
        }
        if (config.shutdownAfterLoad) {
            stopServer();
        }
    }

    /**
     * Returns <code>true</code> if all loaders were started.
     * 
     * @return <code>true</code> if all loaders were started.
     */
    private boolean startStartLoaders() {
        synchronized (this.loaders) {
            // start the loaders
            for (StartupLoader loader : this.loaders) {
                if (this.serverState.get() == ServerState.STOPPING) {
                    return false;
                }
                try {
                    loader.start();
                } catch (StartupException e) {
                    e.printStackTrace();
                    return false;
                }
            }
        }
        return this.serverState.compareAndSet(ServerState.STARTING, ServerState.RUNNING);
    }

    public String status() throws IOException {
        try {
            return sendSocketCommand(Control.STATUS);
        } catch (ConnectException e) {
            return "Not Running";
        } catch (IOException e) {
            throw e;
        }
    }

    public void stopServer() {
        shutdownServer();
        System.exit(0);
    }

    // org.apache.commons.daemon.Daemon.destroy()
    public void destroy() {
        // FIXME: undo init() calls.
    }

    // org.apache.commons.daemon.Daemon.stop()
    public void stop() {
        shutdownServer();
    }

    private class AdminPortThread extends Thread {
        private ServerSocket serverSocket = null;

        AdminPortThread() throws StartupException {
            super("AdminPortThread");
            try {
                this.serverSocket = new ServerSocket(config.adminPort, 1, config.adminAddress);
            } catch (IOException e) {
                throw (StartupException) new StartupException(
                        "Couldn't create server socket(" + config.adminAddress + ":" + config.adminPort + ")")
                                .initCause(e);
            }
            setDaemon(false);
        }

        private void processClientRequest(Socket client) throws IOException {
            BufferedReader reader = null;
            PrintWriter writer = null;
            try {
                reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                String request = reader.readLine();
                writer = new PrintWriter(client.getOutputStream(), true);
                Control control;
                if (request != null && !request.isEmpty() && request.contains(":")) {
                    String key = request.substring(0, request.indexOf(':'));
                    if (key.equals(config.adminKey)) {
                        control = Control.valueOf(request.substring(request.indexOf(':') + 1));
                        if (control == null) {
                            control = Control.FAIL;
                        }
                    } else {
                        control = Control.FAIL;
                    }
                } else {
                    control = Control.FAIL;
                }
                control.processRequest(Start.this, writer);
            } finally {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.flush();
                    writer.close();
                }
            }
        }

        @Override
        public void run() {
            System.out.println("Admin socket configured on - " + config.adminAddress + ":" + config.adminPort);
            while (!Thread.interrupted()) {
                try {
                    Socket clientSocket = serverSocket.accept();
                    System.out.println("Received connection from - " + clientSocket.getInetAddress() + " : "
                            + clientSocket.getPort());
                    processClientRequest(clientSocket);
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}