Java tutorial
/******************************************************************************* * 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(); } } } } }