BATCHEE-132 ensure ServicesManager represents the 'container' of batchee and defines its lifecycle
diff --git a/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java b/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java
index af0f54d..9212839 100755
--- a/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java
@@ -16,18 +16,16 @@
  */

 package org.apache.batchee.container.impl;

 

-import org.apache.batchee.container.Init;

-import org.apache.batchee.container.services.BatchKernelService;

-import org.apache.batchee.container.services.InternalJobExecution;

-import org.apache.batchee.container.services.JobStatusManagerService;

-import org.apache.batchee.container.services.ServicesManager;

-import org.apache.batchee.container.status.JobStatus;

-import org.apache.batchee.jmx.BatchEE;

-import org.apache.batchee.jmx.BatchEEMBean;

-import org.apache.batchee.jmx.BatchEEMBeanImpl;

-import org.apache.batchee.spi.JobExecutionCallbackService;

-import org.apache.batchee.spi.JobXMLLoaderService;

-import org.apache.batchee.spi.PersistenceManagerService;

+import java.io.IOException;

+import java.io.StringWriter;

+import java.sql.Timestamp;

+import java.util.ArrayList;

+import java.util.HashSet;

+import java.util.List;

+import java.util.Properties;

+import java.util.Set;

+import java.util.logging.Level;

+import java.util.logging.Logger;

 

 import javax.batch.operations.JobExecutionAlreadyCompleteException;

 import javax.batch.operations.JobExecutionIsRunningException;

@@ -44,52 +42,23 @@
 import javax.batch.runtime.JobExecution;

 import javax.batch.runtime.JobInstance;

 import javax.batch.runtime.StepExecution;

-import javax.management.MBeanServer;

-import javax.management.ObjectName;

-import java.io.IOException;

-import java.io.StringWriter;

-import java.lang.management.ManagementFactory;

-import java.sql.Timestamp;

-import java.util.ArrayList;

-import java.util.HashSet;

-import java.util.List;

-import java.util.Properties;

-import java.util.Set;

-import java.util.logging.Level;

-import java.util.logging.Logger;

 

-import static org.apache.batchee.container.util.ClassLoaderAwareHandler.makeLoaderAware;

+import org.apache.batchee.container.Init;

+import org.apache.batchee.container.services.BatchKernelService;

+import org.apache.batchee.container.services.InternalJobExecution;

+import org.apache.batchee.container.services.JobStatusManagerService;

+import org.apache.batchee.container.services.ServicesManager;

+import org.apache.batchee.container.status.JobStatus;

+import org.apache.batchee.spi.JobExecutionCallbackService;

+import org.apache.batchee.spi.JobXMLLoaderService;

+import org.apache.batchee.spi.PersistenceManagerService;

 

 

-public class JobOperatorImpl implements JobOperator, AutoCloseable {

+public class JobOperatorImpl implements JobOperator {

     private static final Logger LOGGER = Logger.getLogger(JobOperatorImpl.class.getName());

 

     static {

         Init.doInit();

-

-        if (Boolean.parseBoolean(ServicesManager.value("org.apache.batchee.jmx", "true"))) {

-            try {

-                final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();

-                final String app = ServicesManager.value("org.apache.batchee.jmx.application", "");

-                final ObjectName name;

-                if (app.isEmpty()) {

-                    name = new ObjectName(BatchEEMBean.DEFAULT_OBJECT_NAME);

-                } else {

-                    name = new ObjectName(BatchEEMBean.DEFAULT_OBJECT_NAME + ",application=" + app);

-                }

-

-                if (platformMBeanServer.isRegistered(name)) {

-                    platformMBeanServer.unregisterMBean(name);

-                }

-

-                platformMBeanServer.registerMBean(

-                    new BatchEE(

-                        makeLoaderAware(BatchEEMBean.class, new Class<?>[]{ BatchEEMBean.class }, BatchEEMBeanImpl.INSTANCE)),

-                    name);

-            } catch (final Exception e) {

-                throw new IllegalStateException(e);

-            }

-        }

     }

 

     private final BatchKernelService kernelService;

@@ -115,10 +84,6 @@
         this(ServicesManager.find());

     }

 

-    public void close() throws Exception {

-

-    }

-

     @Override

     public long start(final String jobXMLName, final Properties jobParameters) throws JobStartException, JobSecurityException {

         /*

diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/ServicesManager.java b/jbatch/src/main/java/org/apache/batchee/container/services/ServicesManager.java
index 4aefa33..bd83689 100755
--- a/jbatch/src/main/java/org/apache/batchee/container/services/ServicesManager.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/ServicesManager.java
@@ -17,6 +17,23 @@
  */

 package org.apache.batchee.container.services;

 

+import static org.apache.batchee.container.util.ClassLoaderAwareHandler.makeLoaderAware;

+

+import java.io.Closeable;

+import java.io.IOException;

+import java.io.InputStream;

+import java.lang.management.ManagementFactory;

+import java.lang.reflect.Constructor;

+import java.lang.reflect.InvocationTargetException;

+import java.util.Map;

+import java.util.Properties;

+import java.util.concurrent.ConcurrentHashMap;

+import java.util.logging.Level;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServer;

+import javax.management.ObjectName;

+

 import org.apache.batchee.container.exception.BatchContainerRuntimeException;

 import org.apache.batchee.container.exception.BatchContainerServiceException;

 import org.apache.batchee.container.services.callback.SimpleJobExecutionCallbackService;

@@ -31,6 +48,9 @@
 import org.apache.batchee.container.services.status.DefaultJobStatusManager;

 import org.apache.batchee.container.services.transaction.DefaultBatchTransactionService;

 import org.apache.batchee.container.util.BatchContainerConstants;

+import org.apache.batchee.jmx.BatchEE;

+import org.apache.batchee.jmx.BatchEEMBean;

+import org.apache.batchee.jmx.BatchEEMBeanImpl;

 import org.apache.batchee.spi.BatchArtifactFactory;

 import org.apache.batchee.spi.BatchService;

 import org.apache.batchee.spi.BatchThreadPoolService;

@@ -40,15 +60,6 @@
 import org.apache.batchee.spi.PersistenceManagerService;

 import org.apache.batchee.spi.TransactionManagementService;

 

-import java.io.IOException;

-import java.io.InputStream;

-import java.lang.reflect.Constructor;

-import java.lang.reflect.InvocationTargetException;

-import java.util.Map;

-import java.util.Properties;

-import java.util.concurrent.ConcurrentHashMap;

-import java.util.logging.Logger;

-

 public class ServicesManager implements BatchContainerConstants {

     private final static Logger LOGGER = Logger.getLogger(ServicesManager.class.getName());

 

@@ -77,6 +88,7 @@
 

     private static ServicesManagerLocator servicesManagerLocator;

 

+    private ObjectName jmxName;

     private ClassLoader loader = null;

 

     // designed to be used from app or a server

@@ -147,12 +159,69 @@
 

                     logServices = Boolean.parseBoolean(batchRuntimeConfig.getProperty("batchee.service-manager.log", "false"));

 

+                    if (Boolean.parseBoolean(batchRuntimeConfig.getProperty("org.apache.batchee.jmx", "true"))) {

+                        try {

+                            final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();

+                            final String app = batchRuntimeConfig.getProperty("org.apache.batchee.jmx.application", "");

+                            if (app.isEmpty()) {

+                                jmxName = new ObjectName(BatchEEMBean.DEFAULT_OBJECT_NAME);

+                            } else {

+                                jmxName = new ObjectName(BatchEEMBean.DEFAULT_OBJECT_NAME + ",application=" + app);

+                            }

+

+                            if (!platformMBeanServer.isRegistered(jmxName)) {

+                                platformMBeanServer.registerMBean(

+                                        new BatchEE(

+                                                makeLoaderAware(BatchEEMBean.class, new Class<?>[]{ BatchEEMBean.class },

+                                                        BatchEEMBeanImpl.INSTANCE)),

+                                        jmxName);

+                            } else {

+                                jmxName = null;

+                                LOGGER.warning("You didn't specify org.apache.batchee.jmx.application and JMX is already registered, skipping");

+                            }

+                        } catch (final Exception e) {

+                            throw new IllegalStateException(e);

+                        }

+                    }

+

                     isInited = Boolean.TRUE;

                 }

             }

         }

     }

 

+    public void close() {

+        if (isInited) {

+            synchronized (isInitedLock) {

+                if (isInited) {

+                    service(BatchThreadPoolService.class).shutdown();

+                    synchronized (serviceRegistry) {

+                        for (final Object service : serviceRegistry.values()) {

+                            if (Closeable.class.isInstance(service)) {

+                                try {

+                                    Closeable.class.cast(service).close();

+                                } catch (IOException e) { // don't make it blocking, on j7 we can use suppressed maybe?

+                                    LOGGER.log(Level.SEVERE, e.getMessage(), e);

+                                }

+                            }

+                        }

+                    }

+

+

+                    if (jmxName != null) { // unregister jmx bean if deployed in an app

+                        final MBeanServer jmx = ManagementFactory.getPlatformMBeanServer();

+                        try {

+                            jmx.unregisterMBean(jmxName);

+                        } catch (final Exception e) {

+                            // no-op

+                        }

+                    }

+                    isInited = false;

+                }

+            }

+        }

+    }

+

     public <T extends BatchService> T service(final Class<T> clazz) throws BatchContainerServiceException {

         T service = clazz.cast(serviceRegistry.get(clazz.getName()));

         if (service == null) {

diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java b/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
index 7453059..15eb5ca 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
@@ -22,7 +22,6 @@
 import java.io.ObjectOutputStream;
 import java.lang.reflect.Method;
 import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
 import java.sql.Timestamp;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -46,7 +45,7 @@
 
     public static final String BATCHEE_DATA_PREFIX = "BatchEE_data" + BATCHEE_SPLIT_TOKEN;
 
-    private static final Charset UTF8_CHARSET = StandardCharsets.UTF_8;
+    private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
 
     private static final Logger LOGGER = Logger.getLogger(DefaultDataRepresentationService.class.getName());
 
@@ -298,7 +297,7 @@
             Class<?> typeClass = getClassLoader().loadClass(typeVal);
             Method method = typeClass.getMethod(methodName, paramType);
             return method.invoke(null, valueVal);
-        } catch (ReflectiveOperationException e) {
+        } catch (Exception e) {
             throw new BatchContainerServiceException("Cannot convert data [" + valueVal + "] of type [" + typeVal + "]", e );
         }
     }
diff --git a/jbatch/src/main/java/org/apache/batchee/jmx/BatchEEMBeanImpl.java b/jbatch/src/main/java/org/apache/batchee/jmx/BatchEEMBeanImpl.java
index b396ee5..108ce42 100644
--- a/jbatch/src/main/java/org/apache/batchee/jmx/BatchEEMBeanImpl.java
+++ b/jbatch/src/main/java/org/apache/batchee/jmx/BatchEEMBeanImpl.java
@@ -41,8 +41,6 @@
 public class BatchEEMBeanImpl implements BatchEEMBean {
     public static final BatchEEMBeanImpl INSTANCE = new BatchEEMBeanImpl();
 
-    private final JobOperator operator = BatchRuntime.getJobOperator();
-
     private static final String[] JOB_INSTANCES_ATTRIBUTES = { "jobName", "instanceId" };
     private static final TabularType JOB_INSTANCES_TABULAR_TYPE;
     private static final CompositeType JOB_INSTANCES_COMPOSITE_TYPE;
@@ -154,20 +152,24 @@
         // no-op
     }
 
+    private JobOperator operator() { // lazy since we register jmx with the servicesmanager init
+        return BatchRuntime.getJobOperator();
+    }
+
     @Override
     public String[] getJobNames() {
-        final Set<String> jobNames = operator.getJobNames();
+        final Set<String> jobNames = operator().getJobNames();
         return jobNames.toArray(new String[jobNames.size()]);
     }
 
     @Override
     public int getJobInstanceCount(final String jobName) {
-        return operator.getJobInstanceCount(jobName);
+        return operator().getJobInstanceCount(jobName);
     }
 
     @Override
     public TabularData getJobInstances(final String jobName, final int start, final int count) {
-        final List<JobInstance> instances = operator.getJobInstances(jobName, start, count);
+        final List<JobInstance> instances = operator().getJobInstances(jobName, start, count);
 
         try {
             final TabularDataSupport data = new TabularDataSupport(JOB_INSTANCES_TABULAR_TYPE);
@@ -183,7 +185,7 @@
     @Override
     public Long[] getRunningExecutions(final String jobName) {
         try {
-            final List<Long> runningExecutions = operator.getRunningExecutions(jobName);
+            final List<Long> runningExecutions = operator().getRunningExecutions(jobName);
             return runningExecutions.toArray(new Long[runningExecutions.size()]);
         } catch (final NoSuchJobException nsje) {
             return new Long[0];
@@ -192,7 +194,7 @@
 
     @Override
     public TabularData getParameters(final long executionId) {
-        final Properties parameters = operator.getParameters(executionId);
+        final Properties parameters = operator().getParameters(executionId);
         try {
             final TabularDataSupport data = new TabularDataSupport(PROPERTIES_TABULAR_TYPE);
             for (final Map.Entry<Object, Object> entry : parameters.entrySet()) {
@@ -206,7 +208,7 @@
 
     @Override
     public TabularData getJobInstance(final long executionId) {
-        final JobInstance instance = operator.getJobInstance(executionId);
+        final JobInstance instance = operator().getJobInstance(executionId);
         try {
             final TabularDataSupport data = new TabularDataSupport(JOB_INSTANCES_TABULAR_TYPE);
             data.put(new CompositeDataSupport(JOB_INSTANCES_COMPOSITE_TYPE, JOB_INSTANCES_ATTRIBUTES, new Object[] { instance.getJobName(), instance.getInstanceId() }));
@@ -218,27 +220,27 @@
 
     @Override
     public void stop(final long executionId) {
-        operator.stop(executionId);
+        operator().stop(executionId);
     }
 
     @Override
     public void abandon(final long executionId) {
-        operator.abandon(executionId);
+        operator().abandon(executionId);
     }
 
     @Override
     public long start(final String jobXMLName, final String jobParameters) {
-        return operator.start(jobXMLName, toProperties(jobParameters));
+        return operator().start(jobXMLName, toProperties(jobParameters));
     }
 
     @Override
     public long restart(final long executionId, final String restartParameters) {
-        return operator.restart(executionId, toProperties(restartParameters));
+        return operator().restart(executionId, toProperties(restartParameters));
     }
 
     @Override
     public TabularData getJobExecutions(final long id, final String name) {
-        final List<JobExecution> executions = operator.getJobExecutions(new JobInstanceImpl(id, name));
+        final List<JobExecution> executions = operator().getJobExecutions(new JobInstanceImpl(id, name));
         try {
             final TabularDataSupport data = new TabularDataSupport(JOB_EXECUTION_TABULAR_TYPE);
             for (final JobExecution n : executions) {
@@ -252,7 +254,7 @@
 
     @Override
     public TabularData getJobExecution(final long executionId) {
-        final JobExecution execution = operator.getJobExecution(executionId);
+        final JobExecution execution = operator().getJobExecution(executionId);
         try {
             final TabularDataSupport data = new TabularDataSupport(JOB_EXECUTION_TABULAR_TYPE);
             data.put(new CompositeDataSupport(JOB_EXECUTION_COMPOSITE_TYPE, JOB_EXECUTION_ATTRIBUTES, asArray(execution)));
@@ -264,7 +266,7 @@
 
     @Override
     public TabularData getStepExecutions(final long jobExecutionId) {
-        final List<StepExecution> executions = operator.getStepExecutions(jobExecutionId);
+        final List<StepExecution> executions = operator().getStepExecutions(jobExecutionId);
         try {
             final TabularDataSupport data = new TabularDataSupport(STEP_EXECUTION_TABULAR_TYPE);
             for (final StepExecution n : executions) {
diff --git a/jbatch/src/main/java/org/apache/batchee/servlet/CleanUpWebappListener.java b/jbatch/src/main/java/org/apache/batchee/servlet/CleanUpWebappListener.java
index 9beef4c..51a3b92 100644
--- a/jbatch/src/main/java/org/apache/batchee/servlet/CleanUpWebappListener.java
+++ b/jbatch/src/main/java/org/apache/batchee/servlet/CleanUpWebappListener.java
@@ -16,16 +16,11 @@
  */
 package org.apache.batchee.servlet;
 
-import org.apache.batchee.container.services.ServicesManager;
-import org.apache.batchee.jmx.BatchEEMBean;
-import org.apache.batchee.spi.BatchThreadPoolService;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.annotation.WebListener;
-import java.lang.management.ManagementFactory;
+
+import org.apache.batchee.container.services.ServicesManager;
 
 @WebListener
 public class CleanUpWebappListener implements ServletContextListener {
@@ -36,20 +31,9 @@
 
     @Override
     public void contextDestroyed(final ServletContextEvent sce) {
-        final BatchThreadPoolService threadPoolService = ServicesManager.find().service(BatchThreadPoolService.class);
-        if (CleanUpWebappListener.class.getClassLoader() == sce.getServletContext().getClassLoader()) {
-            threadPoolService.shutdown();
-
-            // unregister jmx bean if deployed in an app
-            final MBeanServer jmx = ManagementFactory.getPlatformMBeanServer();
-            try {
-                final ObjectName objectName = new ObjectName(BatchEEMBean.DEFAULT_OBJECT_NAME);
-                if (jmx.isRegistered(objectName)) {
-                    jmx.unregisterMBean(objectName);
-                }
-            } catch (final Exception e) {
-                // no-op
-            }
+        final ServicesManager servicesManager = ServicesManager.find();
+        if (ServicesManager.class.getClassLoader() == sce.getServletContext().getClassLoader()) {
+            servicesManager.close();
         }
     }
 }
diff --git a/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java b/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
index e5fba15..617f9db 100644
--- a/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
+++ b/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
@@ -129,7 +129,7 @@
             Class<?> clazz = Class.forName(className);
             Method now = clazz.getMethod("now");
             return now.invoke(null);
-        } catch (ReflectiveOperationException e) {
+        } catch (Exception e) {
             // all fine, we are just not running on java8
         }
         return null;