You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@batchee.apache.org by rm...@apache.org on 2014/01/04 20:56:48 UTC
git commit: BATCHEE-11 adding lifecycle handling + classloader
building in cli
Updated Branches:
refs/heads/master bdf3ae85e -> 0dd9d2c4d
BATCHEE-11 adding lifecycle handling + classloader building in cli
Project: http://git-wip-us.apache.org/repos/asf/incubator-batchee/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-batchee/commit/0dd9d2c4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-batchee/tree/0dd9d2c4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-batchee/diff/0dd9d2c4
Branch: refs/heads/master
Commit: 0dd9d2c4dabf8296a583225eb2581d57a03549cc
Parents: bdf3ae8
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Sat Jan 4 20:53:56 2014 +0100
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Sat Jan 4 20:53:56 2014 +0100
----------------------------------------------------------------------
.../container/services/ServicesManager.java | 9 +-
.../factory/CDIBatchArtifactFactory.java | 3 +-
.../factory/DefaultBatchArtifactFactory.java | 14 +-
tools/cli/pom.xml | 21 +++
.../java/org/apache/batchee/cli/BatchEECLI.java | 3 +-
.../org/apache/batchee/cli/command/Abandon.java | 2 +-
.../apache/batchee/cli/command/Executions.java | 2 +-
.../apache/batchee/cli/command/Instances.java | 2 +-
.../batchee/cli/command/JobOperatorCommand.java | 156 +++++++++++++++++++
.../org/apache/batchee/cli/command/Running.java | 2 +-
.../batchee/cli/command/StartableCommand.java | 2 +-
.../org/apache/batchee/cli/command/Status.java | 2 +-
.../org/apache/batchee/cli/command/Stop.java | 2 +-
.../apache/batchee/cli/lifecycle/Lifecycle.java | 27 ++++
.../cli/lifecycle/impl/CdiCtrlLifecycle.java | 36 +++++
.../lifecycle/impl/EJBContainerLifecycle.java | 31 ++++
.../cli/lifecycle/impl/LifecycleBase.java | 51 ++++++
.../cli/lifecycle/impl/SpringLifecycle.java | 114 ++++++++++++++
.../java/org/apache/batchee/cli/MainTest.java | 23 +++
19 files changed, 485 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/jbatch/src/main/java/org/apache/batchee/container/services/ServicesManager.java
----------------------------------------------------------------------
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 8418127..892ae61 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
@@ -163,13 +163,18 @@ public class ServicesManager implements BatchContainerConstants {
}
private <T extends BatchService> T loadService(final Class<T> serviceType) {
+ final Object existing = batchRuntimeConfig.get(serviceType.getName());
+ if (serviceType.isInstance(existing)) {
+ return serviceType.cast(existing);
+ }
+
T service = null;
- String className = batchRuntimeConfig.getProperty(serviceType.getSimpleName());
+ String className = batchRuntimeConfig.getProperty(serviceType.getSimpleName()); // short name first
try {
if (className != null) {
service = load(serviceType, className);
} else {
- className = batchRuntimeConfig.getProperty(serviceType.getName());
+ className = String.class.cast(existing);
if (className != null) {
service = load(serviceType, className);
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/jbatch/src/main/java/org/apache/batchee/container/services/factory/CDIBatchArtifactFactory.java
----------------------------------------------------------------------
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/factory/CDIBatchArtifactFactory.java b/jbatch/src/main/java/org/apache/batchee/container/services/factory/CDIBatchArtifactFactory.java
index 97b9983..c719430 100755
--- a/jbatch/src/main/java/org/apache/batchee/container/services/factory/CDIBatchArtifactFactory.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/factory/CDIBatchArtifactFactory.java
@@ -18,7 +18,6 @@ package org.apache.batchee.container.services.factory;
import org.apache.batchee.container.cdi.BatchCDIInjectionExtension;
import org.apache.batchee.container.exception.BatchContainerServiceException;
-import org.apache.batchee.spi.BatchArtifactFactory;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
@@ -29,7 +28,7 @@ import java.io.IOException;
import java.util.Properties;
import java.util.Set;
-public class CDIBatchArtifactFactory extends DefaultBatchArtifactFactory implements BatchArtifactFactory {
+public class CDIBatchArtifactFactory extends DefaultBatchArtifactFactory {
@Override
public Instance load(final String batchId) {
try {
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/jbatch/src/main/java/org/apache/batchee/container/services/factory/DefaultBatchArtifactFactory.java
----------------------------------------------------------------------
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/factory/DefaultBatchArtifactFactory.java b/jbatch/src/main/java/org/apache/batchee/container/services/factory/DefaultBatchArtifactFactory.java
index 5171aa8..c477b4b 100755
--- a/jbatch/src/main/java/org/apache/batchee/container/services/factory/DefaultBatchArtifactFactory.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/factory/DefaultBatchArtifactFactory.java
@@ -47,7 +47,7 @@ public class DefaultBatchArtifactFactory implements BatchArtifactFactory, XMLStr
@Override
public Instance load(final String batchId) {
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
- final ArtifactMap artifactMap = createArtifactsMap(tccl);
+ final ArtifactLocator artifactMap = createArtifactsLocator(tccl);
Object loadedArtifact = artifactMap.getArtifactById(batchId);
if (loadedArtifact == null) {
@@ -72,7 +72,7 @@ public class DefaultBatchArtifactFactory implements BatchArtifactFactory, XMLStr
return new Instance(loadedArtifact, null);
}
- private ArtifactMap createArtifactsMap(final ClassLoader tccl) {
+ protected ArtifactLocator createArtifactsLocator(final ClassLoader tccl) {
final ArtifactMap artifactMap = new ArtifactMap();
initArtifactMapFromClassLoader(artifactMap, tccl, BATCH_XML);
initArtifactMapFromClassLoader(artifactMap, tccl, BATCHEE_XML);
@@ -183,7 +183,11 @@ public class DefaultBatchArtifactFactory implements BatchArtifactFactory, XMLStr
}
}
- private class ArtifactMap {
+ protected static interface ArtifactLocator {
+ Object getArtifactById(String id);
+ }
+
+ private class ArtifactMap implements ArtifactLocator {
private Map<String, Class<?>> idToArtifactClassMap = new HashMap<String, Class<?>>();
// Maps to a list of types not a single type since there's no reason a single artifact couldn't be annotated
@@ -219,7 +223,8 @@ public class DefaultBatchArtifactFactory implements BatchArtifactFactory, XMLStr
}
}
- private Object getArtifactById(final String id) {
+ @Override
+ public Object getArtifactById(final String id) {
Object artifactInstance = null;
try {
@@ -241,6 +246,5 @@ public class DefaultBatchArtifactFactory implements BatchArtifactFactory, XMLStr
@Override
public void init(final Properties batchConfig) throws BatchContainerServiceException {
// no-op
-
}
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/pom.xml
----------------------------------------------------------------------
diff --git a/tools/cli/pom.xml b/tools/cli/pom.xml
index 57384e7..098d20d 100644
--- a/tools/cli/pom.xml
+++ b/tools/cli/pom.xml
@@ -61,6 +61,27 @@
<version>3.1</version>
</dependency>
+ <!-- for lifecycles -->
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-ejb_3.1_spec</artifactId>
+ <version>1.0.2</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.deltaspike.cdictrl</groupId>
+ <artifactId>deltaspike-cdictrl-api</artifactId>
+ <version>0.5</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>4.0.0.RELEASE</version>
+ <optional>true</optional>
+ </dependency>
+
+
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/BatchEECLI.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/BatchEECLI.java b/tools/cli/src/main/java/org/apache/batchee/cli/BatchEECLI.java
index b5e6dce..f472b26 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/BatchEECLI.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/BatchEECLI.java
@@ -42,7 +42,8 @@ public class BatchEECLI {
final Cli<Runnable> parser = builder.build();
try {
- parser.parse(args).run();
+ final Runnable cmd = parser.parse(args);
+ cmd.run();
} catch (final ParseException e) {
parser.parse("help").run();
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/Abandon.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/Abandon.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/Abandon.java
index 8c8e240..c4ea4f7 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/Abandon.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/Abandon.java
@@ -25,7 +25,7 @@ public class Abandon extends JobOperatorCommand {
private long id;
@Override
- public void run() {
+ public void doRun() {
operator().abandon(id);
info("Abandonned batch " + id);
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/Executions.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/Executions.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/Executions.java
index 3af4a04..321a49e 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/Executions.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/Executions.java
@@ -30,7 +30,7 @@ public class Executions extends JobOperatorCommand {
private long id;
@Override
- public void run() {
+ public void doRun() {
final List<JobExecution> executions = operator().getJobExecutions(new JobInstanceImpl(id));
if (!executions.isEmpty()) {
info("Executions of " + executions.iterator().next().getJobName() + " for instance " + id);
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/Instances.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/Instances.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/Instances.java
index c0e1c6d..f2ae55a 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/Instances.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/Instances.java
@@ -35,7 +35,7 @@ public class Instances extends JobOperatorCommand {
private int count = 100;
@Override
- public void run() {
+ public void doRun() {
final JobOperator operator = operator();
final long total = operator.getJobInstanceCount(name);
info(name + " has " + total + " job instances");
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/JobOperatorCommand.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/JobOperatorCommand.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/JobOperatorCommand.java
index feb62ad..3d4e621 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/JobOperatorCommand.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/JobOperatorCommand.java
@@ -17,6 +17,8 @@
package org.apache.batchee.cli.command;
import io.airlift.command.Option;
+import org.apache.batchee.cli.lifecycle.Lifecycle;
+import org.apache.batchee.container.exception.BatchContainerRuntimeException;
import org.apache.batchee.jaxrs.client.BatchEEJAXRSClientFactory;
import org.apache.batchee.jaxrs.client.ClientConfiguration;
import org.apache.batchee.jaxrs.client.ClientSecurity;
@@ -24,7 +26,25 @@ import org.apache.batchee.jaxrs.client.ClientSslConfiguration;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+import java.util.LinkedList;
+import static java.lang.Thread.currentThread;
+
+/**
+ * base class handling:
+ * - classloader enriched with libs folders (and subfolders)
+ * - Lifecycle (allow to start/stop a container)
+ *
+ * Note: the classloader is created from libs command, it is handy to organize batches
+ * by folders to be able to run them contextual using this command.
+*/
public abstract class JobOperatorCommand implements Runnable {
@Option(name = "-url", description = "when using JAXRS the batchee resource url")
private String baseUrl = null;
@@ -68,6 +88,15 @@ public abstract class JobOperatorCommand implements Runnable {
@Option(name = "-trustManagerProvider", description = "when using JAXRS the trustManagerProvider")
private String trustManagerProvider = null;
+ @Option(name = "-lifecycle", description = "the lifecycle class to use")
+ private String lifecycle = null;
+
+ @Option(name = "-libs", description = "folder containing additional libraries, the folder is added too to the loader")
+ private String libs = null;
+
+ @Option(name = "-shared-libs", description = "folder containing shared libraries, the folder is added too to the loader")
+ private String sharedLibs = null;
+
protected JobOperator operator() {
if (baseUrl == null) {
return BatchRuntime.getJobOperator();
@@ -101,4 +130,131 @@ public abstract class JobOperatorCommand implements Runnable {
protected void info(final String text) {
System.out.println(text);
}
+
+ protected abstract void doRun();
+
+ @Override
+ public final void run() {
+ final ClassLoader oldLoader = currentThread().getContextClassLoader();
+ final ClassLoader loader;
+ try {
+ loader = createLoader(oldLoader);
+ } catch (final MalformedURLException e) {
+ throw new BatchContainerRuntimeException(e);
+ }
+
+ if (loader != oldLoader) {
+ currentThread().setContextClassLoader(loader);
+ }
+
+ try {
+ final Lifecycle<Object> lifecycleInstance;
+ final Object state;
+ if (lifecycle != null) {
+ lifecycleInstance = createLifecycle(loader);
+ state = lifecycleInstance.start();
+ } else {
+ lifecycleInstance = null;
+ state = null;
+ }
+
+ try {
+ doRun();
+ } finally {
+ if (lifecycleInstance != null) {
+ lifecycleInstance.stop(state);
+ }
+ }
+ } finally {
+ currentThread().setContextClassLoader(oldLoader);
+ }
+ }
+
+ private Lifecycle<Object> createLifecycle(final ClassLoader loader) {
+ // some shortcuts are nicer to use from CLI
+ if ("ejbcontainer".equalsIgnoreCase(lifecycle)) {
+ lifecycle = "org.apache.batchee.cli.lifecycle.impl.EJBContainerLifecycle";
+ } else if ("cdi".equalsIgnoreCase(lifecycle)) {
+ lifecycle = "org.apache.batchee.cli.lifecycle.impl.CdiCtrlLifecycle";
+ } else if ("spring".equalsIgnoreCase(lifecycle)) {
+ lifecycle = "org.apache.batchee.cli.lifecycle.impl.SpringLifecycle";
+ }
+
+ try {
+ return (Lifecycle<Object>) loader.loadClass(lifecycle).newInstance();
+ } catch (final Exception e) {
+ throw new BatchContainerRuntimeException(e);
+ }
+ }
+
+ private ClassLoader createLoader(final ClassLoader parent) throws MalformedURLException {
+ if (libs == null) {
+ return parent;
+ }
+
+ final File folder = new File(libs);
+ if (!folder.exists()) {
+ return parent;
+ }
+
+ // we add libs/*.jar and libs/xxx/*.jar to be able to sort libs but only one level to keep it simple
+ final Collection<URL> urls = new LinkedList<URL>();
+ addFolder(folder, urls);
+ if (sharedLibs != null) { // add it later to let specific libs be taken before
+ addFolder(new File(sharedLibs), urls);
+ }
+
+ return new URLClassLoader(urls.toArray(new URL[urls.size()]), parent);
+ }
+
+ private void addFolder(File folder, Collection<URL> urls) throws MalformedURLException {
+ if (!folder.exists()) {
+ return;
+ }
+
+ addJars(folder, urls);
+
+ final File[] subFolders = folder.listFiles(DirFilter.INSTANCE);
+ if (subFolders != null) {
+ for (final File f : subFolders) {
+ addJars(f, urls);
+ }
+ }
+ }
+
+ private static void addJars(final File folder, final Collection<URL> urls) throws MalformedURLException {
+ final File[] additionals = folder.listFiles(JarFilter.INSTANCE);
+ if (additionals != null) {
+ for (final File toAdd : additionals) {
+ urls.add(toAdd.toURI().toURL());
+ }
+ }
+ urls.add(folder.toURI().toURL());
+ }
+
+ private static class JarFilter implements FilenameFilter {
+ public static final FilenameFilter INSTANCE = new JarFilter();
+
+ private JarFilter() {
+ // no-op
+ }
+
+ @Override
+ public boolean accept(final File dir, final String name) {
+ return dir.isFile() && (name.endsWith(".jar") || name.endsWith(".zip"));
+ }
+ }
+
+ private static class DirFilter implements FileFilter {
+ public static final FileFilter INSTANCE = new DirFilter();
+
+ private DirFilter() {
+ // no-op
+ }
+
+ @Override
+ public boolean accept(final File dir) {
+ return dir.isDirectory() && !dir.getName().startsWith(".");
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/Running.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/Running.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/Running.java
index 6c5bddc..5ec4f15 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/Running.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/Running.java
@@ -30,7 +30,7 @@ import java.util.Set;
@Command(name = "running", description = "list running batches")
public class Running extends JobOperatorCommand {
@Override
- public void run() {
+ public void doRun() {
final JobOperator operator = operator();
final Set<String> names = operator.getJobNames();
if (names == null || names.isEmpty()) {
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/StartableCommand.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/StartableCommand.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/StartableCommand.java
index ad7c92b..7440bc1 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/StartableCommand.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/StartableCommand.java
@@ -39,7 +39,7 @@ public abstract class StartableCommand extends JobOperatorCommand {
protected List<String> properties;
@Override
- public void run() {
+ public void doRun() {
final JobOperator operator = operator();
final long id = doStart(operator);
if (wait) {
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/Status.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/Status.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/Status.java
index 1b60a19..109cc73 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/Status.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/Status.java
@@ -29,7 +29,7 @@ import java.util.Set;
@Command(name = "status", description = "list last batches statuses")
public class Status extends JobOperatorCommand {
@Override
- public void run() {
+ public void doRun() {
final JobOperator operator = operator();
final Set<String> names = operator.getJobNames();
if (names == null || names.isEmpty()) {
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/command/Stop.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/command/Stop.java b/tools/cli/src/main/java/org/apache/batchee/cli/command/Stop.java
index 80a9bec..c65d0f6 100644
--- a/tools/cli/src/main/java/org/apache/batchee/cli/command/Stop.java
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/command/Stop.java
@@ -25,7 +25,7 @@ public class Stop extends JobOperatorCommand {
private long id;
@Override
- public void run() {
+ public void doRun() {
operator().stop(id);
info("Stopped batch " + id);
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/Lifecycle.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/Lifecycle.java b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/Lifecycle.java
new file mode 100644
index 0000000..e27ed29
--- /dev/null
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/Lifecycle.java
@@ -0,0 +1,27 @@
+/*
+ * 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.apache.batchee.cli.lifecycle;
+
+/**
+ * Handle before/after hooks for each command.
+ *
+ * @param <T> the state type
+ */
+public interface Lifecycle<T> {
+ T start();
+ void stop(T state);
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/CdiCtrlLifecycle.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/CdiCtrlLifecycle.java b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/CdiCtrlLifecycle.java
new file mode 100644
index 0000000..e688463
--- /dev/null
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/CdiCtrlLifecycle.java
@@ -0,0 +1,36 @@
+/*
+ * 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.apache.batchee.cli.lifecycle.impl;
+
+import org.apache.deltaspike.cdise.api.CdiContainer;
+import org.apache.deltaspike.cdise.api.CdiContainerLoader;
+
+public class CdiCtrlLifecycle extends LifecycleBase<CdiContainer> {
+ @Override
+ public CdiContainer start() {
+ final CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
+ cdiContainer.boot(configuration("cdictrl"));
+ cdiContainer.getContextControl().startContexts();
+ return cdiContainer;
+ }
+
+ @Override
+ public void stop(final CdiContainer cdiContainer) {
+ cdiContainer.getContextControl().stopContexts();
+ cdiContainer.shutdown();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/EJBContainerLifecycle.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/EJBContainerLifecycle.java b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/EJBContainerLifecycle.java
new file mode 100644
index 0000000..c899567
--- /dev/null
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/EJBContainerLifecycle.java
@@ -0,0 +1,31 @@
+/*
+ * 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.apache.batchee.cli.lifecycle.impl;
+
+import javax.ejb.embeddable.EJBContainer;
+
+public class EJBContainerLifecycle extends LifecycleBase<EJBContainer> {
+ @Override
+ public EJBContainer start() {
+ return EJBContainer.createEJBContainer(configuration("ejbcontainer"));
+ }
+
+ @Override
+ public void stop(final EJBContainer state) {
+ state.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/LifecycleBase.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/LifecycleBase.java b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/LifecycleBase.java
new file mode 100644
index 0000000..be7cf2d
--- /dev/null
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/LifecycleBase.java
@@ -0,0 +1,51 @@
+/*
+ * 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.apache.batchee.cli.lifecycle.impl;
+
+import org.apache.batchee.cli.lifecycle.Lifecycle;
+import org.apache.batchee.container.exception.BatchContainerRuntimeException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Properties;
+
+public abstract class LifecycleBase<T> implements Lifecycle<T> {
+ protected static final String LIFECYCLE_PROPERTIES_FILE = "batchee-lifecycle.properties";
+
+ protected Map<?, ?> configuration(final String name) {
+ final String propPath = System.getProperty("batchee.lifecycle." + name + ".properties-path", LIFECYCLE_PROPERTIES_FILE);
+
+ final Properties p = new Properties();
+ final File f = new File(propPath);
+ if (f.isFile()) {
+ try {
+ final InputStream is = new FileInputStream(f);
+ try {
+ p.load(is);
+ } finally {
+ is.close();
+ }
+ } catch (final Exception e) {
+ throw new BatchContainerRuntimeException(e);
+ }
+ }
+
+ return p;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/SpringLifecycle.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/SpringLifecycle.java b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/SpringLifecycle.java
new file mode 100644
index 0000000..ce4cc71
--- /dev/null
+++ b/tools/cli/src/main/java/org/apache/batchee/cli/lifecycle/impl/SpringLifecycle.java
@@ -0,0 +1,114 @@
+/*
+ * 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.apache.batchee.cli.lifecycle.impl;
+
+import org.apache.batchee.container.exception.BatchContainerRuntimeException;
+import org.apache.batchee.container.services.ServicesManager;
+import org.apache.batchee.container.services.ServicesManagerLocator;
+import org.apache.batchee.container.services.factory.DefaultBatchArtifactFactory;
+import org.apache.batchee.spi.BatchArtifactFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Properties;
+
+import static java.lang.Thread.currentThread;
+import static java.util.Arrays.asList;
+
+public class SpringLifecycle extends LifecycleBase<AbstractApplicationContext> {
+ @Override
+ public AbstractApplicationContext start() {
+ final Map<?, ?> config = configuration("spring");
+
+ final AbstractApplicationContext ctx;
+ if (config.containsKey("locations")) {
+ final Collection<String> locations = new LinkedList<String>();
+ locations.addAll(asList(String.class.cast(config.get("locations")).split(",")));
+ ctx = new ClassPathXmlApplicationContext(locations.toArray(new String[locations.size()]));
+ } else if (config.containsKey("classes")) {
+ final Collection<Class<?>> classes = new LinkedList<Class<?>>();
+ final ClassLoader loader = currentThread().getContextClassLoader();
+ for (final String clazz : String.class.cast(config.get("classes")).split(",")) {
+ try {
+ classes.add(loader.loadClass(clazz));
+ } catch (final ClassNotFoundException e) {
+ throw new BatchContainerRuntimeException(e);
+ }
+ }
+ ctx = new AnnotationConfigApplicationContext(classes.toArray(new Class<?>[classes.size()]));
+ } else {
+ throw new IllegalArgumentException(LIFECYCLE_PROPERTIES_FILE + " should contain 'classes' or 'locations' key");
+ }
+
+ final Properties p = new Properties();
+ p.put(BatchArtifactFactory.class.getName(), new SpringArtifactFactory(ctx));
+
+ final ServicesManager mgr = new ServicesManager();
+ mgr.init(p);
+
+ ServicesManager.setServicesManagerLocator(new ServicesManagerLocator() {
+ @Override
+ public ServicesManager find() {
+ return mgr;
+ }
+ });
+
+ return ctx;
+ }
+
+ @Override
+ public void stop(final AbstractApplicationContext state) {
+ state.close();
+ }
+
+ public static class SpringArtifactFactory extends DefaultBatchArtifactFactory {
+ private final ApplicationContext context;
+
+ public SpringArtifactFactory(final ApplicationContext ctx) {
+ context = ctx;
+ }
+
+ @Override
+ protected ArtifactLocator createArtifactsLocator(final ClassLoader tccl) {
+ return new SpringArtifactLocator(super.createArtifactsLocator(tccl), context);
+ }
+
+ private static class SpringArtifactLocator implements ArtifactLocator {
+ private final ArtifactLocator parent;
+ private final ApplicationContext context;
+
+ public SpringArtifactLocator(final ArtifactLocator parent, final ApplicationContext context) {
+ this.parent = parent;
+ this.context = context;
+ }
+
+ @Override
+ public Object getArtifactById(final String id) {
+ final Object bean = context.getBean(id);
+ if (bean != null) {
+ return bean;
+ }
+ return parent.getArtifactById(id);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/0dd9d2c4/tools/cli/src/test/java/org/apache/batchee/cli/MainTest.java
----------------------------------------------------------------------
diff --git a/tools/cli/src/test/java/org/apache/batchee/cli/MainTest.java b/tools/cli/src/test/java/org/apache/batchee/cli/MainTest.java
index acdc071..0d966ba 100644
--- a/tools/cli/src/test/java/org/apache/batchee/cli/MainTest.java
+++ b/tools/cli/src/test/java/org/apache/batchee/cli/MainTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.batchee.cli;
+import org.apache.batchee.cli.lifecycle.Lifecycle;
import org.apache.batchee.util.Batches;
import org.junit.Rule;
import org.junit.Test;
@@ -26,6 +27,7 @@ import javax.batch.runtime.BatchRuntime;
import static org.apache.batchee.cli.BatchEECLI.main;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class MainTest {
@@ -150,4 +152,25 @@ public class MainTest {
Batches.waitForEnd(jobOperator, id);
}
+
+ @Test
+ public void lifecycle() {
+ // whatever child of JobOperatorCommand so using running which is simple
+ main(new String[]{ "running", "-lifecycle", MyLifecycle.class.getName() });
+ assertEquals("start stop", MyLifecycle.result);
+ }
+
+ public static class MyLifecycle implements Lifecycle<String> {
+ private static String result;
+
+ @Override
+ public String start() {
+ return "start";
+ }
+
+ @Override
+ public void stop(final String state) {
+ result = state + " stop";
+ }
+ }
}