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/03/27 07:48:07 UTC

git commit: BATCHEE-16 adding a way to select the classloader to use to run the batch from the gui

Repository: incubator-batchee
Updated Branches:
  refs/heads/master f5b540cc1 -> f3534e29e


BATCHEE-16 adding a way to select the classloader to use to run the batch from the gui


Project: http://git-wip-us.apache.org/repos/asf/incubator-batchee/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-batchee/commit/f3534e29
Tree: http://git-wip-us.apache.org/repos/asf/incubator-batchee/tree/f3534e29
Diff: http://git-wip-us.apache.org/repos/asf/incubator-batchee/diff/f3534e29

Branch: refs/heads/master
Commit: f3534e29e7d66cf887bc3d5b30c82e94d51eb2c7
Parents: f5b540c
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Thu Mar 27 07:47:44 2014 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Thu Mar 27 07:47:44 2014 +0100

----------------------------------------------------------------------
 gui/servlet/pom.xml                             |  7 ++
 .../batchee/servlet/JBatchController.java       | 55 +++++++++++++-
 .../spi/JobOperatorClassLoaderFinder.java       | 26 +++++++
 .../OpenEJBJobOperatorClassLoaderFinder.java    | 75 ++++++++++++++++++++
 4 files changed, 162 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/f3534e29/gui/servlet/pom.xml
----------------------------------------------------------------------
diff --git a/gui/servlet/pom.xml b/gui/servlet/pom.xml
index d635301..a4e540f 100644
--- a/gui/servlet/pom.xml
+++ b/gui/servlet/pom.xml
@@ -49,6 +49,13 @@
     </dependency>
 
     <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>openejb-core</artifactId>
+      <version>4.6.0</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-frontend-jaxrs</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/f3534e29/gui/servlet/src/main/java/org/apache/batchee/servlet/JBatchController.java
----------------------------------------------------------------------
diff --git a/gui/servlet/src/main/java/org/apache/batchee/servlet/JBatchController.java b/gui/servlet/src/main/java/org/apache/batchee/servlet/JBatchController.java
index 87cf32b..cbd119b 100644
--- a/gui/servlet/src/main/java/org/apache/batchee/servlet/JBatchController.java
+++ b/gui/servlet/src/main/java/org/apache/batchee/servlet/JBatchController.java
@@ -16,6 +16,8 @@
  */
 package org.apache.batchee.servlet;
 
+import org.apache.batchee.servlet.spi.JobOperatorClassLoaderFinder;
+
 import javax.batch.operations.BatchRuntimeException;
 import javax.batch.operations.JobExecutionNotRunningException;
 import javax.batch.operations.JobOperator;
@@ -33,6 +35,9 @@ import java.io.ByteArrayOutputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -55,12 +60,15 @@ public class JBatchController extends HttpServlet {
     private static final String START_MAPPING = "/start/";
     private static final String DO_START_MAPPING = "/doStart/";
     private static final String VIEW_MAPPING = "/view/";
+    public static final String BATCHEE_CLASSLOADER_FINDER_KEY = "batchee.classloader-finder";
 
     private JobOperator operator;
 
     private String context;
     private String mapping = DEFAULT_MAPPING_SERVLET25;
     private int executionByPage = DEFAULT_PAGE_SIZE;
+    private ClassLoader controllerLoader;
+    private JobOperatorClassLoaderFinder classLoaderFinder;
 
     public JBatchController mapping(final String rawMapping) {
         this.mapping = rawMapping.substring(0, rawMapping.length() - 2); // mapping pattern is /xxx/*
@@ -74,7 +82,29 @@ public class JBatchController extends HttpServlet {
 
     @Override
     public void init(final ServletConfig config) throws ServletException {
-        this.operator = BatchRuntime.getJobOperator();
+        controllerLoader = Thread.currentThread().getContextClassLoader();
+
+        final JobOperator delegate = BatchRuntime.getJobOperator();
+        classLoaderFinder = newClassLoaderFinder(
+                System.getProperty(BATCHEE_CLASSLOADER_FINDER_KEY, config.getInitParameter(BATCHEE_CLASSLOADER_FINDER_KEY)),
+                controllerLoader);
+
+        this.operator = JobOperator.class.cast(Proxy.newProxyInstance(
+                controllerLoader,
+                new Class<?>[] { JobOperator.class },
+                new InvocationHandler() {
+                    @Override
+                    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+                        final Thread thread = Thread.currentThread();
+                        final ClassLoader original = thread.getContextClassLoader();
+                        thread.setContextClassLoader(findLoaderToUse(original, method.getName(), args));
+                        try {
+                            return method.invoke(delegate, args);
+                        } finally {
+                            thread.setContextClassLoader(original);
+                        }
+                    }
+                }));
 
         this.context = config.getServletContext().getContextPath();
         if ("/".equals(context)) {
@@ -84,6 +114,29 @@ public class JBatchController extends HttpServlet {
         mapping = context + mapping;
     }
 
+    private JobOperatorClassLoaderFinder newClassLoaderFinder(final String initParameter, final ClassLoader webappLoader) {
+        if (initParameter == null) {
+            return null;
+        }
+        try {
+            return JobOperatorClassLoaderFinder.class.cast(
+                    controllerLoader.loadClass(initParameter.trim()).getConstructor(ClassLoader.class)
+                            .newInstance(webappLoader));
+        } catch (final Exception e) {
+            throw new BatchRuntimeException(e.getMessage(), e);
+        }
+    }
+
+    protected ClassLoader findLoaderToUse(final ClassLoader original, String name, Object[] args) {
+        if (classLoaderFinder != null) {
+            final ClassLoader found = classLoaderFinder.find(name, args);
+            if (found != null) {
+                return found;
+            }
+        }
+        return original;
+    }
+
     @Override
     protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
         resp.setContentType("text/html");

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/f3534e29/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/JobOperatorClassLoaderFinder.java
----------------------------------------------------------------------
diff --git a/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/JobOperatorClassLoaderFinder.java b/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/JobOperatorClassLoaderFinder.java
new file mode 100644
index 0000000..f1f715d
--- /dev/null
+++ b/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/JobOperatorClassLoaderFinder.java
@@ -0,0 +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.apache.batchee.servlet.spi;
+
+public interface JobOperatorClassLoaderFinder {
+    /**
+     * @param name JobOperator method
+     * @param args arguments of the method
+     * @return
+     */
+    ClassLoader find(String name, Object[] args);
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/f3534e29/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/internal/OpenEJBJobOperatorClassLoaderFinder.java
----------------------------------------------------------------------
diff --git a/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/internal/OpenEJBJobOperatorClassLoaderFinder.java b/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/internal/OpenEJBJobOperatorClassLoaderFinder.java
new file mode 100644
index 0000000..e65b620
--- /dev/null
+++ b/gui/servlet/src/main/java/org/apache/batchee/servlet/spi/internal/OpenEJBJobOperatorClassLoaderFinder.java
@@ -0,0 +1,75 @@
+/*
+ * 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.servlet.spi.internal;
+
+import org.apache.batchee.servlet.spi.JobOperatorClassLoaderFinder;
+import org.apache.openejb.AppContext;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.ContainerSystem;
+
+import java.util.List;
+import java.util.Properties;
+
+// simple impl taking just *the* other app if tomee deploys a single application
+// or a specific one if you specifiy in properties batchee.application
+//
+// side note: it needs the persistence to be shared accross apps (case in a server or with database usage)
+public class OpenEJBJobOperatorClassLoaderFinder implements JobOperatorClassLoaderFinder {
+    private static final String BATCHEE_APPLICATION = "batchee.application";
+
+    private final ClassLoader ignoreLoader;
+
+    public OpenEJBJobOperatorClassLoaderFinder(final ClassLoader ignoreLoader) {
+        this.ignoreLoader = ignoreLoader;
+    }
+
+    @Override
+    public ClassLoader find(final String name, final Object[] args) {
+        final String idToFind = extractId(name, args);
+
+        ClassLoader potentialLoader = null;
+
+        final List<AppContext> appContexts = SystemInstance.get().getComponent(ContainerSystem.class).getAppContexts();
+        for (final AppContext app : appContexts) {
+            final  String id = app.getId();
+            if ("tomee".equals(id) || "openejb".equals(id)) {
+                continue;
+            }
+
+            potentialLoader = app.getClassLoader();
+            if (potentialLoader == ignoreLoader) {
+                continue;
+            }
+
+            if (id.equals(idToFind)) {
+                return potentialLoader;
+            }
+        }
+        return potentialLoader;
+    }
+
+    private String extractId(final String name, final Object[] args) {
+        if (args != null) {
+            for (final Object o : args) {
+                if (Properties.class.isInstance(o)) {
+                    return Properties.class.cast(o).getProperty(BATCHEE_APPLICATION);
+                }
+            }
+        }
+        return null;
+    }
+}