svn commit: r1745351 - /ofbiz/trunk/framework/start/src/org/ofbiz/base/start/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1745351 - /ofbiz/trunk/framework/start/src/org/ofbiz/base/start/

Taher Alkhateeb
Author: taher
Date: Tue May 24 12:26:28 2016
New Revision: 1745351

URL: http://svn.apache.org/viewvc?rev=1745351&view=rev
Log:
major commit to start component - for OFBIZ-6783

This is another major refactoring exercise of the start
component in ofbiz. There are too many details in this commit
that may be summarized as follows:

- refactor Start.java to make it about 140 lines long and focused
  only on high level function calls. Also minimized the number of
  class fields (state) to only two (ServerState and Config)
- Separate the AdminPortThread into a new class with some refactoring
  done to ensure interoperability with other classes
- delete CommonsDaemonStart as jsvc is not yet fully implemented in ofbiz
  and it stands in the way of a proper refactoring of ofbiz
- refactor everything so that all dependencies between classes are explicit
  through function calls (no hidden state or declarations)
- Move all the server processing logic (status, shutdown, start ...) to a
  new class called StartupControlPanel. All methods in this class are static
  with side effects only limited to the arguments passed to them.
- Add a few missing apache copyright headers
- Refactoring some method, variable and enum names to make them clearer
- Refactor Config.java and make it much cleaner and simpler by breaking
  things down into private methods. Also changed the portoffset to be
  a normal int instead of a boxed int (Integer)
- redefine most classes to be package protected (not public) to offer
  more isolation from the rest of the framework
- redefine most classes to be final

Added:
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java   (with props)
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java   (with props)
Removed:
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/CommonsDaemonStart.java
Modified:
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Instrumenter.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumenterWorker.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommand.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommandUtil.java
    ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupException.java

Added: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java?rev=1745351&view=auto
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java (added)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java Tue May 24 12:26:28 2016
@@ -0,0 +1,99 @@
+package org.ofbiz.base.start;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.ofbiz.base.start.Start.ServerState;
+import org.ofbiz.base.start.StartupControlPanel.OfbizSocketCommand;
+
+final class AdminPortThread extends Thread {
+    private ServerSocket serverSocket = null;
+    private ArrayList<StartupLoader> loaders = null;
+    private AtomicReference<ServerState> serverState = null;
+    private Config config = null;
+
+    AdminPortThread(ArrayList<StartupLoader> loaders, AtomicReference<ServerState> serverState, Config config) throws StartupException {
+        super("OFBiz-AdminPortThread");
+        try {
+            this.serverSocket = new ServerSocket(config.adminPort, 1, config.adminAddress);
+        } catch (IOException e) {
+            throw new StartupException("Couldn't create server socket(" + config.adminAddress + ":" + config.adminPort + ")",
+                    e);
+        }
+        setDaemon(false);
+        this.loaders = loaders;
+        this.serverState = serverState;
+        this.config = config;
+    }
+
+    private void processClientRequest(Socket client, ArrayList<StartupLoader> loaders, AtomicReference<ServerState> serverState) 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);
+            OfbizSocketCommand control;
+            if (request != null && !request.isEmpty() && request.contains(":")) {
+                String key = request.substring(0, request.indexOf(':'));
+                if (key.equals(config.adminKey)) {
+                    control = OfbizSocketCommand.valueOf(request.substring(request.indexOf(':') + 1));
+                    if (control == null) {
+                        control = OfbizSocketCommand.FAIL;
+                    }
+                } else {
+                    control = OfbizSocketCommand.FAIL;
+                }
+            } else {
+                control = OfbizSocketCommand.FAIL;
+            }
+            switch(control) {
+            case SHUTDOWN:
+                if (serverState.get() == ServerState.STOPPING) {
+                    writer.println("IN-PROGRESS");
+                } else {
+                    writer.println("OK");
+                    writer.flush();
+                    StartupControlPanel.stopServer(loaders, serverState, this);
+                }
+                break;
+            case STATUS:
+                writer.println(serverState.get());
+                break;
+            case FAIL:
+                writer.println("FAIL");
+                break;
+            }
+        } 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, loaders, serverState);
+                clientSocket.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/AdminPortThread.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Classpath.java Tue May 24 12:26:28 2016
@@ -34,7 +34,7 @@ import java.util.StringTokenizer;
  * <p>You can build a class path by repeatedly calling the addXxx methods,
  * then use the getXxx methods to get the accumulated class path.</p>
  */
-public class Classpath {
+public final class Classpath {
 
     private static final String nativeLibExt = System.mapLibraryName("someLib").replace("someLib", "").toLowerCase();
     private List<File> elements = new ArrayList<File>();

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Config.java Tue May 24 12:26:28 2016
@@ -35,127 +35,164 @@ import java.util.Optional;
 import java.util.Properties;
 import java.util.TimeZone;
 
-public class Config {
+public final class Config {
 
+    public final String ofbizHome;
+    public final String awtHeadless;
     public final InetAddress adminAddress;
     public final String adminKey;
+    public final int portOffset;
     public final int adminPort;
-    public final String awtHeadless;
     public final String containerConfig;
     public final String instrumenterClassName;
     public final String instrumenterFile;
     public final List<Map<String, String>> loaders;
     public final String logDir;
-    public final String ofbizHome;
     public final boolean shutdownAfterLoad;
     public final String splashLogo;
     public final boolean useShutdownHook;
-    public final Integer portOffset;
     public final String classpathAddComponent;
     public final String classpathAddFilesFromPath;
 
     Config(List<StartupCommand> ofbizCommands) throws StartupException {
-        String fileName = determineOfbizPropertiesFileName(ofbizCommands);
-        String config = "org/ofbiz/base/start/" + fileName + ".properties";
+
+        // fetch OFBiz Properties object
         Properties props;
         try {
-            props = this.getPropertiesFile(config);
+            props = getPropertiesFile(ofbizCommands);
         } catch (IOException e) {
             throw new StartupException(e);
         }
-        System.out.println("Start.java using configuration file " + config);
-        
-        // set portOffsetValue
-        int portOffsetValue = 0;
-        Optional<StartupCommand> portOffsetCommand = ofbizCommands.stream()
-                .filter(command -> command.getName().equals(StartupCommandUtil.StartupOption.PORTOFFSET.getName()))
-                .findFirst();
-        if(portOffsetCommand.isPresent()) {
-            Map<String,String> commandArgs = portOffsetCommand.get().getProperties();
-            try {
-                portOffsetValue = Integer.parseInt(commandArgs.keySet().iterator().next());
-            } catch(NumberFormatException e) {
-                throw new StartupException("invalid portoffset number", e);
-            }
-        }
 
-        // set the ofbiz.home
-        String ofbizHomeTmp = props.getProperty("ofbiz.home", ".");
-        // get a full path
-        if (ofbizHomeTmp.equals(".")) {
-            ofbizHomeTmp = System.getProperty("user.dir");
-            ofbizHomeTmp = ofbizHomeTmp.replace('\\', '/');
-        }
-        ofbizHome = ofbizHomeTmp;
-        System.setProperty("ofbiz.home", ofbizHome);
-        System.out.println("Set OFBIZ_HOME to - " + ofbizHome);
-        // Class paths
+        // set this class fields
+        ofbizHome = getOfbizHome(props);
+        awtHeadless = getProperty(props, "java.awt.headless", "false");
+        adminAddress = getAdminAddress(props);
+        adminKey = getProperty(props, "ofbiz.admin.key", "NA");
+        portOffset = getPortOffsetValue(ofbizCommands);
+        adminPort = getAdminPort(props, portOffset);
+        containerConfig = getAbsolutePath(props, "ofbiz.container.config", "framework/base/config/ofbiz-containers.xml", ofbizHome);
+        instrumenterClassName = getProperty(props, "ofbiz.instrumenterClassName", null);
+        instrumenterFile = getProperty(props, "ofbiz.instrumenterFile", null);
+        loaders = getLoaders(props);
+        logDir = getAbsolutePath(props, "ofbiz.log.dir", "runtime/logs", ofbizHome);
+        shutdownAfterLoad = isShutdownAfterLoad(props);
+        splashLogo = props.getProperty("ofbiz.start.splash.logo", null);
+        useShutdownHook = isUseShutdownHook(props);
         classpathAddComponent = props.getProperty("ofbiz.start.classpath.addComponent");
         classpathAddFilesFromPath = props.getProperty("ofbiz.start.classpath.addFilesFromPath");
-        // log directory
-        logDir = getOfbizHomeProp(props, "ofbiz.log.dir", "runtime/logs");
 
-        // container configuration
-        containerConfig = getOfbizHomeProp(props, "ofbiz.container.config", "framework/base/config/ofbiz-containers.xml");
+        System.out.println("Set OFBIZ_HOME to - " + ofbizHome);
 
-        // get the admin server info
-        String serverHost = getProp(props, "ofbiz.admin.host", "127.0.0.1");
+        // set system properties
+        System.setProperty("ofbiz.home", ofbizHome);
+        System.setProperty("java.awt.headless", awtHeadless);
+        System.setProperty("derby.system.home", getProperty(props, "derby.system.home", "runtime/data/derby"));
 
-        String adminPortStr = getProp(props, "ofbiz.admin.port", "0");
-        // set the admin key
-        adminKey = getProp(props, "ofbiz.admin.key", "NA");
+        // set the default locale
+        setDefaultLocale(props);
 
-        // create the host InetAddress
-        try {
-            adminAddress = InetAddress.getByName(serverHost);
-        } catch (UnknownHostException e) {
-            throw new StartupException(e);
+        // set the default timezone
+        String tzString = props.getProperty("ofbiz.timeZone.default");
+        if (tzString != null && tzString.length() > 0) {
+            TimeZone.setDefault(TimeZone.getTimeZone(tzString));
         }
+    }
 
-        // parse the port number
-        int adminPortTmp;
-        try {
-            adminPortTmp = Integer.parseInt(adminPortStr);
-            adminPortTmp = adminPortTmp != 0 ? adminPortTmp : 10523; // This is necessary because the ASF machines don't allow ports 1 to 3, see  INFRA-6790
-            adminPortTmp += portOffsetValue;
-        } catch (Exception e) {
-            System.out.println("Error while parsing admin port number (so default to 10523) = " + e);
-            adminPortTmp = 10523;
+    private String getAbsolutePath(Properties props, String key, String def, String ofbizHome) {
+        String value = System.getProperty(key);
+        if (value != null) {
+            return value;
+        } else {
+            return ofbizHome + "/" + props.getProperty(key, def);
         }
-        adminPort = adminPortTmp;
-
-        // set the Derby system home
-        String derbyPath = getProp(props, "derby.system.home", "runtime/data/derby");
-        System.setProperty("derby.system.home", derbyPath);
+    }
 
-        // check for shutdown hook
-        if (System.getProperty("ofbiz.enable.hook") != null && System.getProperty("ofbiz.enable.hook").length() > 0) {
-            useShutdownHook = "true".equalsIgnoreCase(System.getProperty("ofbiz.enable.hook"));
-        } else if (props.getProperty("ofbiz.enable.hook") != null && props.getProperty("ofbiz.enable.hook").length() > 0) {
-            useShutdownHook = "true".equalsIgnoreCase(props.getProperty("ofbiz.enable.hook"));
+    private String getProperty(Properties props, String key, String defaultValue) {
+        String value = System.getProperty(key);
+        if (value != null) {
+            return value;
         } else {
-            useShutdownHook = true;
+            return props.getProperty(key, defaultValue);
         }
+    }
 
-        // check for auto-shutdown
-        if (System.getProperty("ofbiz.auto.shutdown") != null && System.getProperty("ofbiz.auto.shutdown").length() > 0) {
-            shutdownAfterLoad = "true".equalsIgnoreCase(System.getProperty("ofbiz.auto.shutdown"));
-        } else if (props.getProperty("ofbiz.auto.shutdown") != null && props.getProperty("ofbiz.auto.shutdown").length() > 0) {
-            shutdownAfterLoad = "true".equalsIgnoreCase(props.getProperty("ofbiz.auto.shutdown"));
-        } else {
-            shutdownAfterLoad = false;
+    private Properties getPropertiesFile(List<StartupCommand> ofbizCommands) throws IOException {
+        String fileName = determineOfbizPropertiesFileName(ofbizCommands);
+        String fullyQualifiedFileName = "org/ofbiz/base/start/" + fileName + ".properties";
+        InputStream propsStream = null;
+        Properties props = new Properties();
+        try {
+            // first try classpath
+            propsStream = getClass().getClassLoader().getResourceAsStream(fullyQualifiedFileName);
+            if (propsStream != null) {
+                props.load(propsStream);
+            } else {
+                throw new IOException();
+            }
+        } catch (IOException e) {
+            // next try file location
+            File propsFile = new File(fullyQualifiedFileName);
+            if (propsFile != null) {
+                FileInputStream fis = null;
+                try {
+                    fis = new FileInputStream(propsFile);
+                    if (fis != null) {
+                        props.load(fis);
+                    }
+                } catch (FileNotFoundException e2) {
+                    // do nothing; we will see empty props below
+                } finally {
+                    if (fis != null) {
+                        fis.close();
+                    }
+                }
+            }
+        } finally {
+            if (propsStream != null) {
+                propsStream.close();
+            }
         }
 
-        // set AWT headless mode
-        awtHeadless = getProp(props, "java.awt.headless", null);
-        if (awtHeadless != null) {
-            System.setProperty("java.awt.headless", awtHeadless);
+        // check for empty properties
+        if (props.isEmpty()) {
+            throw new IOException("Cannot load configuration properties : " + fullyQualifiedFileName);
         }
+        System.out.println("Start.java using configuration file " + fullyQualifiedFileName);
+        return props;
+    }
 
-        // get the splash logo
-        splashLogo = props.getProperty("ofbiz.start.splash.logo", null);
+    private String determineOfbizPropertiesFileName(List<StartupCommand> ofbizCommands) {
+        String fileName = null;
+        if (ofbizCommands.stream().anyMatch(command ->
+        command.getName() == StartupCommandUtil.StartupOption.START.getName()
+        || command.getName() == StartupCommandUtil.StartupOption.SHUTDOWN.getName()
+        || command.getName() == StartupCommandUtil.StartupOption.STATUS.getName() )
+        || ofbizCommands.isEmpty()
+        || ofbizCommands.stream().allMatch(command ->
+            command.getName() == StartupCommandUtil.StartupOption.PORTOFFSET.getName())
+                ){
+            fileName = "start";
+        } else if(ofbizCommands.stream().anyMatch(
+                option -> option.getName() == StartupCommandUtil.StartupOption.BOTH.getName())) {
+            fileName = "both";
+        } else if(ofbizCommands.stream().anyMatch(
+                option -> option.getName() == StartupCommandUtil.StartupOption.LOAD_DATA.getName())) {
+            fileName = "load-data";
+        } else if(ofbizCommands.stream().anyMatch(
+                option -> option.getName() == StartupCommandUtil.StartupOption.POS.getName())) {
+            fileName = "pos";
+        } else if(ofbizCommands.stream().anyMatch(
+                option -> option.getName() == StartupCommandUtil.StartupOption.TEST.getName())) {
+            fileName = "test";
+        } else if(ofbizCommands.stream().anyMatch(
+                option -> option.getName() == StartupCommandUtil.StartupOption.TEST_LIST.getName())) {
+            fileName = "testlist";
+        }
+        return fileName;
+    }
 
-        // set the default locale
+    private void setDefaultLocale(Properties props) {
         String localeString = props.getProperty("ofbiz.locale.default");
         if (localeString != null && localeString.length() > 0) {
             String locales[] = localeString.split("_");
@@ -171,17 +208,48 @@ public class Config {
             }
             System.setProperty("user.language", localeString);
         }
+    }
 
-        // set the default time zone
-        String tzString = props.getProperty("ofbiz.timeZone.default");
-        if (tzString != null && tzString.length() > 0) {
-            TimeZone.setDefault(TimeZone.getTimeZone(tzString));
+    private int getPortOffsetValue(List<StartupCommand> ofbizCommands) throws StartupException {
+        int extractedPortOffset = 0;
+        Optional<StartupCommand> portOffsetCommand = ofbizCommands.stream()
+                .filter(command -> command.getName().equals(StartupCommandUtil.StartupOption.PORTOFFSET.getName()))
+                .findFirst();
+        if(portOffsetCommand.isPresent()) {
+            Map<String,String> commandArgs = portOffsetCommand.get().getProperties();
+            try {
+                extractedPortOffset = Integer.parseInt(commandArgs.keySet().iterator().next());
+            } catch(NumberFormatException e) {
+                throw new StartupException("invalid portoffset number", e);
+            }
         }
+        return extractedPortOffset;
+    }
 
-        instrumenterClassName = getProp(props, "ofbiz.instrumenterClassName", null);
-        instrumenterFile = getProp(props, "ofbiz.instrumenterFile", null);
+    private InetAddress getAdminAddress(Properties props) throws StartupException {
+        String serverHost = getProperty(props, "ofbiz.admin.host", "127.0.0.1");
+        try {
+            return InetAddress.getByName(serverHost);
+        } catch (UnknownHostException e) {
+            throw new StartupException(e);
+        }
+    }
 
-        // loader classes
+    private int getAdminPort(Properties props, int portOffsetValue) {
+        String adminPortStr = getProperty(props, "ofbiz.admin.port", "0");
+        int calculatedAdminPort;
+        try {
+            calculatedAdminPort = Integer.parseInt(adminPortStr);
+            calculatedAdminPort = calculatedAdminPort != 0 ? calculatedAdminPort : 10523; // This is necessary because the ASF machines don't allow ports 1 to 3, see  INFRA-6790
+            calculatedAdminPort += portOffsetValue;
+        } catch (Exception e) {
+            System.out.println("Error while parsing admin port number (so default to 10523) = " + e);
+            calculatedAdminPort = 10523;
+        }
+        return calculatedAdminPort;
+    }
+
+    private List<Map<String, String>> getLoaders(Properties props) {
         ArrayList<Map<String, String>> loadersTmp = new ArrayList<Map<String, String>>();
         int currentPosition = 1;
         Map<String, String> loader = null;
@@ -198,95 +266,35 @@ public class Config {
             }
         }
         loadersTmp.trimToSize();
-        loaders = Collections.unmodifiableList(loadersTmp);
-
-        // set the port offset
-        this.portOffset = portOffsetValue;
+        return Collections.unmodifiableList(loadersTmp);
     }
 
-    private String determineOfbizPropertiesFileName(List<StartupCommand> ofbizCommands) {
-        String fileName = null;
-        if (ofbizCommands.stream().anyMatch(command ->
-        command.getName() == StartupCommandUtil.StartupOption.START.getName()
-        || command.getName() == StartupCommandUtil.StartupOption.SHUTDOWN.getName()
-        || command.getName() == StartupCommandUtil.StartupOption.STATUS.getName() )
-        || ofbizCommands.isEmpty()
-        || ofbizCommands.stream().allMatch(command ->
-            command.getName() == StartupCommandUtil.StartupOption.PORTOFFSET.getName())
-                ){
-            fileName = "start";
-        } else if(ofbizCommands.stream().anyMatch(
-                option -> option.getName() == StartupCommandUtil.StartupOption.BOTH.getName())) {
-            fileName = "both";
-        } else if(ofbizCommands.stream().anyMatch(
-                option -> option.getName() == StartupCommandUtil.StartupOption.LOAD_DATA.getName())) {
-            fileName = "load-data";
-        } else if(ofbizCommands.stream().anyMatch(
-                option -> option.getName() == StartupCommandUtil.StartupOption.POS.getName())) {
-            fileName = "pos";
-        } else if(ofbizCommands.stream().anyMatch(
-                option -> option.getName() == StartupCommandUtil.StartupOption.TEST.getName())) {
-            fileName = "test";
-        } else if(ofbizCommands.stream().anyMatch(
-                option -> option.getName() == StartupCommandUtil.StartupOption.TEST_LIST.getName())) {
-            fileName = "testlist";
+    private String getOfbizHome(Properties props) {
+        String extractedOfbizHome = props.getProperty("ofbiz.home", ".");
+        if (extractedOfbizHome.equals(".")) {
+            extractedOfbizHome = System.getProperty("user.dir");
+            extractedOfbizHome = extractedOfbizHome.replace('\\', '/');
         }
-        return fileName;
-    }
-
-    private String getOfbizHomeProp(Properties props, String key, String def) {
-        String value = System.getProperty(key);
-        if (value != null)
-            return value;
-        return ofbizHome + "/" + props.getProperty(key, def);
+        return extractedOfbizHome;
     }
 
-    private String getProp(Properties props, String key, String def) {
-        String value = System.getProperty(key);
-        if (value != null)
-            return value;
-        return props.getProperty(key, def);
-    }
-
-    private Properties getPropertiesFile(String config) throws IOException {
-        InputStream propsStream = null;
-        Properties props = new Properties();
-        try {
-            // first try classpath
-            propsStream = getClass().getClassLoader().getResourceAsStream(config);
-            if (propsStream != null) {
-                props.load(propsStream);
-            } else {
-                throw new IOException();
-            }
-        } catch (IOException e) {
-            // next try file location
-            File propsFile = new File(config);
-            if (propsFile != null) {
-                FileInputStream fis = null;
-                try {
-                    fis = new FileInputStream(propsFile);
-                    if (fis != null) {
-                        props.load(fis);
-                    }
-                } catch (FileNotFoundException e2) {
-                    // do nothing; we will see empty props below
-                } finally {
-                    if (fis != null) {
-                        fis.close();
-                    }
-                }
-            }
-        } finally {
-            if (propsStream != null) {
-                propsStream.close();
-            }
+    private boolean isShutdownAfterLoad(Properties props) {
+        if (System.getProperty("ofbiz.auto.shutdown") != null && System.getProperty("ofbiz.auto.shutdown").length() > 0) {
+            return "true".equalsIgnoreCase(System.getProperty("ofbiz.auto.shutdown"));
+        } else if (props.getProperty("ofbiz.auto.shutdown") != null && props.getProperty("ofbiz.auto.shutdown").length() > 0) {
+            return "true".equalsIgnoreCase(props.getProperty("ofbiz.auto.shutdown"));
+        } else {
+            return false;
         }
+    }
 
-        // check for empty properties
-        if (props.isEmpty()) {
-            throw new IOException("Cannot load configuration properties : " + config);
+    private boolean isUseShutdownHook(Properties props) {
+        if (System.getProperty("ofbiz.enable.hook") != null && System.getProperty("ofbiz.enable.hook").length() > 0) {
+            return "true".equalsIgnoreCase(System.getProperty("ofbiz.enable.hook"));
+        } else if (props.getProperty("ofbiz.enable.hook") != null && props.getProperty("ofbiz.enable.hook").length() > 0) {
+            return "true".equalsIgnoreCase(props.getProperty("ofbiz.enable.hook"));
+        } else {
+            return true;
         }
-        return props;
     }
 }

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Instrumenter.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Instrumenter.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Instrumenter.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Instrumenter.java Tue May 24 12:26:28 2016
@@ -21,7 +21,7 @@ package org.ofbiz.base.start;
 import java.io.File;
 import java.io.IOException;
 
-public interface Instrumenter {
+interface Instrumenter {
     File getDefaultFile() throws IOException;
     void open(File dataFile, boolean forInstrumenting) throws IOException;
     byte[] instrumentClass(byte[] bytes) throws IOException;

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumenterWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumenterWorker.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumenterWorker.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumenterWorker.java Tue May 24 12:26:28 2016
@@ -40,7 +40,7 @@ import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
-public final class InstrumenterWorker {
+final class InstrumenterWorker {
 
     public static final void copy(InputStream in, OutputStream out) throws IOException {
         byte[] buf = new byte[4096];

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/InstrumentingClassLoader.java Tue May 24 12:26:28 2016
@@ -37,7 +37,7 @@ import java.util.zip.ZipOutputStream;
 /*
  * Instrumenting class loader.
  */
-public final class InstrumentingClassLoader extends NativeLibClassLoader {
+final class InstrumentingClassLoader extends NativeLibClassLoader {
 
     private static final void copy(InputStream in, OutputStream out) throws IOException {
         byte[] buf = new byte[4096];

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/Start.java Tue May 24 12:26:28 2016
@@ -18,20 +18,8 @@
  *******************************************************************************/
 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.PrintWriter;
-import java.net.ConnectException;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
 
 /**
  * OFBiz startup class.
@@ -53,10 +41,7 @@ import java.util.stream.Collectors;
 public final class Start {
 
     private Config config = null;
-    private final List<String> loaderArgs = new ArrayList<String>();
-    private final ArrayList<StartupLoader> loaders = new ArrayList<StartupLoader>();
     private final AtomicReference<ServerState> serverState = new AtomicReference<ServerState>(ServerState.STARTING);
-    private Thread adminPortThread = null;
 
     // Singleton, do not change
     private static final Start instance = new Start();
@@ -76,28 +61,27 @@ public final class Start {
             ofbizCommands = StartupCommandUtil.parseOfbizCommands(args);
         } catch (StartupException e) {
             // incorrect arguments passed to the command line
-            StartupCommandUtil.printAndHighlightMessage(e.getMessage());
+            StartupCommandUtil.highlightAndPrintErrorMessage(e.getMessage());
             StartupCommandUtil.printOfbizStartupHelp(System.err);
             System.exit(1);
         }
 
         CommandType commandType = evaluateOfbizCommands(ofbizCommands);
-        if(commandType != CommandType.HELP) {
-            instance.init(ofbizCommands);
+        if(!commandType.equals(CommandType.HELP)) {
+            instance.config = StartupControlPanel.init(ofbizCommands);
         }
         switch (commandType) {
             case HELP:
                 StartupCommandUtil.printOfbizStartupHelp(System.out);
                 break;
             case STATUS:
-                System.out.println("Current Status : " + instance.status());
+                System.out.println("Current Status : " + StartupControlPanel.status(instance.config));
                 break;
             case SHUTDOWN:
-                System.out.println("Shutting down server : " + instance.shutdown());
+                System.out.println("Shutting down server : " + StartupControlPanel.shutdown(instance.config));
                 break;
             case START:
-                populateLoaderArgs(ofbizCommands);
-                instance.start();
+                StartupControlPanel.start(instance.config, instance.serverState, ofbizCommands);
                 break;
         }
     }
@@ -135,77 +119,6 @@ public final class Start {
         }
     }
 
-    void init(List<StartupCommand> ofbizCommands) throws StartupException {
-        loadGlobalOfbizSystemProperties("ofbiz.system.props");
-        try {
-            this.config = new Config(ofbizCommands);
-        } catch (StartupException e) {
-            throw new StartupException("Could not fetch config instance", e);
-        }
-    }
-
-    void start() throws StartupException {
-        // create the log directory
-        createLogDirectory();
-        // create the listener thread
-        createListenerThread();
-        // set the shutdown hook
-        if (config.useShutdownHook) {
-            Runtime.getRuntime().addShutdownHook(new Thread() {
-                @Override
-                public void run() {
-                    shutdownServer();
-                }
-            });
-        } else {
-            System.out.println("Shutdown hook disabled");
-        }
-
-        // initialize the startup loaders
-        initStartLoaders();
-        if (!startStartLoaders()) {
-            if (this.serverState.get() == ServerState.STOPPING) {
-                return;
-            } else {
-                throw new StartupException("Error during start.");
-            }
-        }
-        if (config.shutdownAfterLoad) {
-            stopServer();
-        }
-    }
-
-    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();
-        }
-    }
-
-    void stopServer() {
-        shutdownServer();
-        System.exit(0);
-    }
-
     private static CommandType evaluateOfbizCommands(List<StartupCommand> ofbizCommands) {
         if (ofbizCommands.stream().anyMatch(
                 command -> command.getName().equals(StartupCommandUtil.StartupOption.HELP.getName()))) {
@@ -224,329 +137,4 @@ public final class Start {
     private enum CommandType {
         HELP, STATUS, SHUTDOWN, START
     }
-
-    private void loadGlobalOfbizSystemProperties(String globalOfbizPropertiesFileName) throws StartupException {
-        String globalSystemPropsFileName = System.getProperty(globalOfbizPropertiesFileName);
-        if (globalSystemPropsFileName != null) {
-            FileInputStream stream = null;
-            try {
-                stream = new FileInputStream(globalSystemPropsFileName);
-                System.getProperties().load(stream);
-            } catch (IOException e) {
-                throw new StartupException("Couldn't load global system props", e);
-            } finally {
-                if (stream != null) {
-                    try {
-                        stream.close();
-                    } catch (IOException e) {
-                        throw new StartupException("Couldn't close stream", e);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * populates the loaderArgs with arguments as expected by the
-     * containers that will receive them.
-     *
-     * TODO A better solution is to change the signature of all
-     * containers to receive a <tt>List</tt> of <tt>StartupCommand</tt>s
-     * instead and delete the methods populateLoaderArgs, commandExistsInList
-     * and retrieveCommandArgumentEntries along with the loaderArgs list.
-     */
-    private static void populateLoaderArgs(List<StartupCommand> ofbizCommands) {
-        final String LOAD_DATA = StartupCommandUtil.StartupOption.LOAD_DATA.getName();
-        final String TEST = StartupCommandUtil.StartupOption.TEST.getName();
-        final String TEST_LIST = StartupCommandUtil.StartupOption.TEST_LIST.getName();
-        
-        if(commandExistsInList(ofbizCommands, LOAD_DATA)) {
-            retrieveCommandArguments(ofbizCommands, LOAD_DATA).entrySet().stream().forEach(entry ->
-            instance.loaderArgs.add("-" + entry.getKey() + "=" + entry.getValue()));
-        } else if(commandExistsInList(ofbizCommands, TEST)) {
-            retrieveCommandArguments(ofbizCommands, TEST).entrySet().stream().forEach(entry ->
-            instance.loaderArgs.add("-" + entry.getKey() + "=" + entry.getValue()));
-        } else if(commandExistsInList(ofbizCommands, TEST_LIST)) {
-            Map<String,String> testListArgs = retrieveCommandArguments(ofbizCommands, TEST_LIST);
-            instance.loaderArgs.add(testListArgs.get("file"));
-            instance.loaderArgs.add("-" + testListArgs.get("mode"));
-        }
-    }
-
-    private static boolean commandExistsInList(List<StartupCommand> ofbizCommands, String commandName) {
-        return ofbizCommands.stream().anyMatch(command -> command.getName().equals(commandName));
-    }
-
-    private static Map<String,String> retrieveCommandArguments(List<StartupCommand> ofbizCommands, String commandName) {
-        return ofbizCommands.stream()
-                .filter(option-> option.getName().equals(commandName))
-                .collect(Collectors.toList()).get(0).getProperties();
-    }
-
-    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() + "]");
-            }
-        }
-    }
-
-    private NativeLibClassLoader createClassLoader() throws IOException {
-        ClassLoader parent = Thread.currentThread().getContextClassLoader();
-        if (parent instanceof NativeLibClassLoader) {
-            parent = parent.getParent();
-        }
-        if (parent == null) {
-            parent = Start.class.getClassLoader();
-            if (parent == null) {
-                parent = ClassLoader.getSystemClassLoader();
-            }
-        }
-        Classpath classPath = new Classpath();
-        /*
-         * Class paths needed to get StartupLoaders to work.
-         */
-        classPath.addComponent(config.ofbizHome);
-        String ofbizHomeTmp = config.ofbizHome;
-        if (!ofbizHomeTmp.isEmpty() && !ofbizHomeTmp.endsWith("/")) {
-            ofbizHomeTmp = ofbizHomeTmp.concat("/");
-        }
-        if (config.classpathAddComponent != null) {
-            String[] components = config.classpathAddComponent.split(",");
-            for (String component : components) {
-                classPath.addComponent(ofbizHomeTmp.concat(component.trim()));
-            }
-        }
-        if (config.classpathAddFilesFromPath != null) {
-            String[] paths = config.classpathAddFilesFromPath.split(",");
-            for (String path : paths) {
-                classPath.addFilesFromPath(new File(ofbizHomeTmp.concat(path.trim())));
-            }
-        }
-        NativeLibClassLoader classloader = new NativeLibClassLoader(classPath.getUrls(), parent);
-        if (config.instrumenterFile != null && config.instrumenterClassName != null) {
-            try {
-                classloader = new InstrumentingClassLoader(classPath.getUrls(), parent, config.instrumenterFile,
-                        config.instrumenterClassName);
-            } catch (Exception e) {
-                System.out.println("Instrumenter not enabled - " + e);
-            }
-        }
-        classloader.addNativeClassPath(System.getProperty("java.library.path"));
-        for (File folder : classPath.getNativeFolders()) {
-            classloader.addNativeClassPath(folder);
-        }
-        return classloader;
-    }
-
-    private void initStartLoaders() throws StartupException {
-        NativeLibClassLoader classloader = null;
-        try {
-            classloader = createClassLoader();
-        } catch (IOException e) {
-            throw new StartupException("Couldn't create NativeLibClassLoader", e);
-        }
-        Thread.currentThread().setContextClassLoader(classloader);
-        String[] argsArray = loaderArgs.toArray(new String[loaderArgs.size()]);
-        synchronized (this.loaders) {
-            for (Map<String, String> loaderMap : config.loaders) {
-                if (this.serverState.get() == ServerState.STOPPING) {
-                    return;
-                }
-                try {
-                    String loaderClassName = loaderMap.get("class");
-                    Class<?> loaderClass = classloader.loadClass(loaderClassName);
-                    StartupLoader loader = (StartupLoader) loaderClass.newInstance();
-                    loaders.add(loader); // add before loading, so unload can occur if error during loading
-                    loader.load(config, argsArray);
-                } catch (ClassNotFoundException e) {
-                    throw new StartupException(e.getMessage(), e);
-                } catch (InstantiationException e) {
-                    throw new StartupException(e.getMessage(), e);
-                } catch (IllegalAccessException e) {
-                    throw new StartupException(e.getMessage(), e);
-                }
-            }
-            this.loaders.trimToSize();
-        }
-        if (classloader instanceof InstrumentingClassLoader) {
-            try {
-                ((InstrumentingClassLoader)classloader).closeInstrumenter();
-            } catch (IOException e) {
-                throw new StartupException(e.getMessage(), e);
-            }
-        }
-        StringBuilder sb = new StringBuilder();
-        for (String path : classloader.getNativeLibPaths()) {
-            if (sb.length() > 0) {
-                sb.append(File.pathSeparator);
-            }
-            sb.append(path);
-        }
-        System.setProperty("java.library.path", sb.toString());
-    }
-
-    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;
-    }
-
-    private String shutdown() throws StartupException {
-        try {
-            return sendSocketCommand(Control.SHUTDOWN);
-        } catch (Exception e) {
-            throw new StartupException(e);
-        }
-    }
-
-    /**
-     * @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);
-    }
-
-    private String status() throws StartupException {
-        try {
-            return sendSocketCommand(Control.STATUS);
-        } catch (ConnectException e) {
-            return "Not Running";
-        } catch (IOException e) {
-            throw new StartupException(e);
-        }
-    }
-
-    private class AdminPortThread extends Thread {
-        private ServerSocket serverSocket = null;
-
-        AdminPortThread() throws StartupException {
-            super("OFBiz-AdminPortThread");
-            try {
-                this.serverSocket = new ServerSocket(config.adminPort, 1, config.adminAddress);
-            } catch (IOException e) {
-                throw new StartupException("Couldn't create server socket(" + config.adminAddress + ":" + config.adminPort + ")",
-                        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();
-                }
-            }
-        }
-    }
-
-    private enum Control {
-        SHUTDOWN {
-            @Override
-            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 {
-            @Override
-            void processRequest(Start start, PrintWriter writer) {
-                writer.println(start.serverState.get());
-            }
-        },
-        FAIL {
-            @Override
-            void processRequest(Start start, PrintWriter writer) {
-                writer.println("FAIL");
-            }
-        };
-
-        abstract void processRequest(Start start, PrintWriter writer);
-    }
 }

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommand.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommand.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommand.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommand.java Tue May 24 12:26:28 2016
@@ -1,3 +1,21 @@
+/*******************************************************************************
+ * 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.util.Map;
@@ -11,7 +29,7 @@ import java.util.Map;
  * For example: <code>java -jar ofbiz.jar --status</code> where status is a command.
  * </p>
  */
-public class StartupCommand {
+final class StartupCommand {
     private String name;
     private Map<String,String> properties;
 

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommandUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommandUtil.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommandUtil.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupCommandUtil.java Tue May 24 12:26:28 2016
@@ -1,7 +1,26 @@
+/*******************************************************************************
+ * 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.PrintStream;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -25,7 +44,7 @@ import org.apache.commons.cli.ParseExcep
  * in addition to utility methods for parsing and handling these options
  * </p>
  */
-public final class StartupCommandUtil {
+final class StartupCommandUtil {
 
     /*
      * Make sure of defining the same set of values in:
@@ -184,16 +203,55 @@ public final class StartupCommandUtil {
                 true);
     }
 
-    static final void printAndHighlightMessage(String message) {
+    static final void highlightAndPrintErrorMessage(String errorMessage) {
         System.err.println(
                 "==============================================================================="
                 + System.lineSeparator()
-                + message
+                + errorMessage
                 + System.lineSeparator()
                 + "==============================================================================="
                 );
     }
 
+    /**
+     * Generates the loaderArgs with arguments as expected by the
+     * containers that will receive them.
+     *
+     * TODO A better solution is to change the signature of all
+     * containers to receive a <tt>List</tt> of <tt>StartupCommand</tt>s
+     * instead and delete the methods populateLoaderArgs, commandExistsInList
+     * and retrieveCommandArgumentEntries along with the loaderArgs list.
+     */
+    static List<String> adaptStartupCommandsToLoaderArgs(List<StartupCommand> ofbizCommands) {
+        List<String> loaderArgs = new ArrayList<String>();
+        final String LOAD_DATA = StartupCommandUtil.StartupOption.LOAD_DATA.getName();
+        final String TEST = StartupCommandUtil.StartupOption.TEST.getName();
+        final String TEST_LIST = StartupCommandUtil.StartupOption.TEST_LIST.getName();
+        
+        if(commandExistsInList(ofbizCommands, LOAD_DATA)) {
+            retrieveCommandArguments(ofbizCommands, LOAD_DATA).entrySet().stream().forEach(entry ->
+            loaderArgs.add("-" + entry.getKey() + "=" + entry.getValue()));
+        } else if(commandExistsInList(ofbizCommands, TEST)) {
+            retrieveCommandArguments(ofbizCommands, TEST).entrySet().stream().forEach(entry ->
+            loaderArgs.add("-" + entry.getKey() + "=" + entry.getValue()));
+        } else if(commandExistsInList(ofbizCommands, TEST_LIST)) {
+            Map<String,String> testListArgs = retrieveCommandArguments(ofbizCommands, TEST_LIST);
+            loaderArgs.add(testListArgs.get("file"));
+            loaderArgs.add("-" + testListArgs.get("mode"));
+        }
+        return loaderArgs;
+    }
+
+    private static boolean commandExistsInList(List<StartupCommand> ofbizCommands, String commandName) {
+        return ofbizCommands.stream().anyMatch(command -> command.getName().equals(commandName));
+    }
+
+    private static Map<String,String> retrieveCommandArguments(List<StartupCommand> ofbizCommands, String commandName) {
+        return ofbizCommands.stream()
+                .filter(option-> option.getName().equals(commandName))
+                .collect(Collectors.toList()).get(0).getProperties();
+    }
+
     private static final List<StartupCommand> mapCommonsCliOptionsToStartupCommands(final CommandLine commandLine) {
         List<Option> optionList = Arrays.asList(commandLine.getOptions());
         return optionList.stream()

Added: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java?rev=1745351&view=auto
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java (added)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java Tue May 24 12:26:28 2016
@@ -0,0 +1,293 @@
+/*******************************************************************************
+ * 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.PrintWriter;
+import java.net.ConnectException;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.ofbiz.base.start.Start.ServerState;
+
+final class StartupControlPanel {
+
+    enum OfbizSocketCommand {
+        SHUTDOWN, STATUS, FAIL
+    }
+
+    static Config init(List<StartupCommand> ofbizCommands) throws StartupException {
+        loadGlobalOfbizSystemProperties("ofbiz.system.props");
+        try {
+            return new Config(ofbizCommands);
+        } catch (StartupException e) {
+            throw new StartupException("Could not fetch config instance", e);
+        }
+    }
+
+    static String status(Config config) throws StartupException {
+        try {
+            return sendSocketCommand(OfbizSocketCommand.STATUS, config);
+        } catch (ConnectException e) {
+            return "Not Running";
+        } catch (IOException e) {
+            throw new StartupException(e);
+        }
+    }
+
+    static String shutdown(Config config) throws StartupException {
+        try {
+            return sendSocketCommand(OfbizSocketCommand.SHUTDOWN, config);
+        } catch (Exception e) {
+            throw new StartupException(e);
+        }
+    }
+
+    static void start(Config config,
+            AtomicReference<ServerState> serverState,
+            List<StartupCommand> ofbizCommands) throws StartupException {
+        
+        List<String> loaderArgs = StartupCommandUtil.adaptStartupCommandsToLoaderArgs(ofbizCommands);
+        ArrayList<StartupLoader> loaders = new ArrayList<StartupLoader>();
+        Thread adminPortThread = null;
+
+        //create log dir
+        File logDir = new File(config.logDir);
+        if (!logDir.exists()) {
+            if (logDir.mkdir()) {
+                System.out.println("Created OFBiz log dir [" + logDir.getAbsolutePath() + "]");
+            }
+        }
+
+        // create the listener thread
+        if (config.adminPort > 0) {
+            adminPortThread = new AdminPortThread(loaders, serverState, config);
+            adminPortThread.start();
+        } else {
+            System.out.println("Admin socket not configured; set to port 0");
+        }
+
+        // set the shutdown hook
+        if (config.useShutdownHook) {
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+                @Override
+                public void run() {
+                    StartupControlPanel.shutdownServer(loaders, serverState, this);
+                }
+            });
+        } else {
+            System.out.println("Shutdown hook disabled");
+        }
+
+        // load and start the startup loaders
+        loadStartupLoaders(config, loaderArgs, loaders, serverState);
+        startStartupLoaders(loaders, serverState);
+
+        // execute shutdown if applicable
+        if (config.shutdownAfterLoad) {
+            StartupControlPanel.stopServer(loaders, serverState, adminPortThread);
+        }
+    }
+
+    static void stopServer(ArrayList<StartupLoader> loaders, AtomicReference<ServerState> serverState, Thread adminPortThread) {
+        shutdownServer(loaders, serverState, adminPortThread);
+        System.exit(0);
+    }
+
+    private static void shutdownServer(ArrayList<StartupLoader> loaders, AtomicReference<ServerState> serverState, Thread adminPortThread) {
+        ServerState currentState;
+        do {
+            currentState = serverState.get();
+            if (currentState == ServerState.STOPPING) {
+                return;
+            }
+        } while (!serverState.compareAndSet(currentState, ServerState.STOPPING));
+        // The current thread was the one that successfully changed the state;
+        // continue with further processing.
+        synchronized (loaders) {
+            // Unload in reverse order
+            for (int i = loaders.size(); i > 0; i--) {
+                StartupLoader loader = loaders.get(i - 1);
+                try {
+                    loader.unload();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        if (adminPortThread != null && adminPortThread.isAlive()) {
+            adminPortThread.interrupt();
+        }
+    }
+
+    private static void loadGlobalOfbizSystemProperties(String globalOfbizPropertiesFileName) throws StartupException {
+        String systemProperties = System.getProperty(globalOfbizPropertiesFileName);
+        if (systemProperties != null) {
+            FileInputStream stream = null;
+            try {
+                stream = new FileInputStream(systemProperties);
+                System.getProperties().load(stream);
+                stream.close();
+            } catch (IOException e) {
+                throw new StartupException("Couldn't load global system props", e);
+            }
+        }
+    }
+
+    private static String sendSocketCommand(OfbizSocketCommand socketCommand, Config config) throws IOException {
+        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 + ":" + socketCommand);
+            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;
+    }
+
+    private static NativeLibClassLoader createClassLoader(Config config) throws IOException {
+        ClassLoader parent = Thread.currentThread().getContextClassLoader();
+        if (parent instanceof NativeLibClassLoader) {
+            parent = parent.getParent();
+        }
+        if (parent == null) {
+            parent = Start.class.getClassLoader();
+            if (parent == null) {
+                parent = ClassLoader.getSystemClassLoader();
+            }
+        }
+        Classpath classPath = new Classpath();
+        /*
+         * Class paths needed to get StartupLoaders to work.
+         */
+        classPath.addComponent(config.ofbizHome);
+        String ofbizHomeTmp = config.ofbizHome;
+        if (!ofbizHomeTmp.isEmpty() && !ofbizHomeTmp.endsWith("/")) {
+            ofbizHomeTmp = ofbizHomeTmp.concat("/");
+        }
+        if (config.classpathAddComponent != null) {
+            String[] components = config.classpathAddComponent.split(",");
+            for (String component : components) {
+                classPath.addComponent(ofbizHomeTmp.concat(component.trim()));
+            }
+        }
+        if (config.classpathAddFilesFromPath != null) {
+            String[] paths = config.classpathAddFilesFromPath.split(",");
+            for (String path : paths) {
+                classPath.addFilesFromPath(new File(ofbizHomeTmp.concat(path.trim())));
+            }
+        }
+        NativeLibClassLoader classloader = new NativeLibClassLoader(classPath.getUrls(), parent);
+        if (config.instrumenterFile != null && config.instrumenterClassName != null) {
+            try {
+                classloader = new InstrumentingClassLoader(classPath.getUrls(), parent, config.instrumenterFile,
+                        config.instrumenterClassName);
+            } catch (Exception e) {
+                System.out.println("Instrumenter not enabled - " + e);
+            }
+        }
+        classloader.addNativeClassPath(System.getProperty("java.library.path"));
+        for (File folder : classPath.getNativeFolders()) {
+            classloader.addNativeClassPath(folder);
+        }
+        return classloader;
+    }
+
+    private static void loadStartupLoaders(Config config,
+            List<String> loaderArgs, ArrayList<StartupLoader> loaders,
+            AtomicReference<ServerState> serverState) throws StartupException {
+
+        NativeLibClassLoader classloader = null;
+        try {
+            classloader = createClassLoader(config);
+        } catch (IOException e) {
+            throw new StartupException("Couldn't create NativeLibClassLoader", e);
+        }
+        Thread.currentThread().setContextClassLoader(classloader);
+        String[] argsArray = loaderArgs.toArray(new String[loaderArgs.size()]);
+        synchronized (loaders) {
+            for (Map<String, String> loaderMap : config.loaders) {
+                if (serverState.get() == ServerState.STOPPING) {
+                    return;
+                }
+                try {
+                    String loaderClassName = loaderMap.get("class");
+                    Class<?> loaderClass = classloader.loadClass(loaderClassName);
+                    StartupLoader loader = (StartupLoader) loaderClass.newInstance();
+                    loaders.add(loader); // add before loading, so unload can occur if error during loading
+                    loader.load(config, argsArray);
+                } catch (ReflectiveOperationException e) {
+                    throw new StartupException(e.getMessage(), e);
+                }
+            }
+            loaders.trimToSize();
+        }
+        if (classloader instanceof InstrumentingClassLoader) {
+            try {
+                ((InstrumentingClassLoader)classloader).closeInstrumenter();
+            } catch (IOException e) {
+                throw new StartupException(e.getMessage(), e);
+            }
+        }
+        StringBuilder sb = new StringBuilder();
+        for (String path : classloader.getNativeLibPaths()) {
+            if (sb.length() > 0) {
+                sb.append(File.pathSeparator);
+            }
+            sb.append(path);
+        }
+        System.setProperty("java.library.path", sb.toString());
+    }
+
+    private static void startStartupLoaders(List<StartupLoader> loaders,
+            AtomicReference<ServerState> serverState) throws StartupException {
+
+        synchronized (loaders) {
+            // start the loaders
+            for (StartupLoader loader : loaders) {
+                if (serverState.get() == ServerState.STOPPING) {
+                    return;
+                } else {
+                    loader.start();
+                }
+            }
+        }
+        if(!serverState.compareAndSet(ServerState.STARTING, ServerState.RUNNING)) {
+            throw new StartupException("Error during start");
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupControlPanel.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupException.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupException.java?rev=1745351&r1=1745350&r2=1745351&view=diff
==============================================================================
--- ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupException.java (original)
+++ ofbiz/trunk/framework/start/src/org/ofbiz/base/start/StartupException.java Tue May 24 12:26:28 2016
@@ -23,7 +23,7 @@ package org.ofbiz.base.start;
  *
  */
 @SuppressWarnings("serial")
-public class StartupException extends Exception {
+public final class StartupException extends Exception {
 
     /**
      * Creates new <code>StartupException</code> without detail message.