diff --git a/cave/com.raytheon.uf.viz.common.core.feature/feature.xml b/cave/com.raytheon.uf.viz.common.core.feature/feature.xml index 1686cc4f82..f0666aee66 100644 --- a/cave/com.raytheon.uf.viz.common.core.feature/feature.xml +++ b/cave/com.raytheon.uf.viz.common.core.feature/feature.xml @@ -326,4 +326,11 @@ version="0.0.0" unpack="false"/> + + diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/.classpath b/edexOsgi/com.raytheon.uf.common.python.concurrent/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/.project b/edexOsgi/com.raytheon.uf.common.python.concurrent/.project new file mode 100644 index 0000000000..d2a2a4bca9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.common.python.concurrent + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.python.concurrent/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.python.concurrent/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3a77aae644 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Concurrent +Bundle-SymbolicName: com.raytheon.uf.common.python.concurrent +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: com.raytheon.uf.common.python;bundle-version="1.12.1174" +Export-Package: com.raytheon.uf.common.python.concurrent diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/build.properties b/edexOsgi/com.raytheon.uf.common.python.concurrent/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/AbstractPythonScriptFactory.java b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/AbstractPythonScriptFactory.java new file mode 100644 index 0000000000..1b4cebfb3b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/AbstractPythonScriptFactory.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.python.concurrent; + +import com.raytheon.uf.common.python.PythonInterpreter; + +/** + * Must be extended by all classes that want to run Python on different threads. + * Defines the thread pool, gets the {@link PythonInterpreter}, and tells how to + * execute. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 5, 2013            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public abstract class AbstractPythonScriptFactory

{ + + private final int maxThreads; + + private final String name; + + /** + * This method will be called on the Python thread and will instantiate the + * PythonInterpreter that is going to be used. + * + * @return + */ + public abstract P createPythonScript(); + + public AbstractPythonScriptFactory(String name, int maxThreads) { + this.name = name; + this.maxThreads = maxThreads; + } + + /** + * @return the maxThreads + */ + public final int getMaxThreads() { + return maxThreads; + } + + /** + * @return the name + */ + public final String getName() { + return name; + } +} diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/IPythonExecutor.java b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/IPythonExecutor.java new file mode 100644 index 0000000000..91941f5575 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/IPythonExecutor.java @@ -0,0 +1,51 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.python.concurrent; + +import com.raytheon.uf.common.python.PythonInterpreter; + +/** + * Any class that implements this will be able to execute methods on the + * PythonInterpreter that is passed in + * + *

+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 5, 2013            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public interface IPythonExecutor

{ + /** + * Method takes a {@link PythonInterpreter} and executes the necessary parts + * of it + * + * @param script + * @return + */ + public abstract R execute(P script); +} diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/IPythonJobListener.java b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/IPythonJobListener.java new file mode 100644 index 0000000000..b50765daac --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/IPythonJobListener.java @@ -0,0 +1,56 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.python.concurrent; + +import java.util.EventListener; + +/** + * Subclasses can create their own instance of this class to specify what to do + * when the {@link PythonJob} is finished + * + *

+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 30, 2013            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public interface IPythonJobListener extends EventListener { + /** + * When a job has finished successfully this will get fired. + * + * @param result + */ + public void jobFinished(R result); + + /** + * When a job has finished with exceptions, this will get fired. + * + * @param e + */ + public void jobFailed(Throwable e); +} diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonJob.java b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonJob.java new file mode 100644 index 0000000000..c3eeedea8d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonJob.java @@ -0,0 +1,79 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.python.concurrent; + +import java.util.concurrent.Callable; + +import com.raytheon.uf.common.python.PythonInterpreter; + +/** + * Task that will invoke methods on a {@link IPythonExecutor} subclass + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 31, 2013            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ +public class PythonJob

+ implements Callable { + + /* + * When code creates a new PythonJob, this gets set to the instance of the + * ThreadLocal that corresponds with whichever thread the application is + * running on + */ + private ThreadLocal

threadPython = null; + + private IPythonJobListener listener; + + private IPythonExecutor executor; + + public PythonJob(IPythonExecutor executor, + IPythonJobListener listener, ThreadLocal

threadLocal, + Object... args) { + this.listener = listener; + this.threadPython = threadLocal; + this.executor = executor; + } + + @Override + public R call() { + P script = threadPython.get(); + R result = null; + try { + result = executor.execute(script); + } catch (Throwable t) { + listener.jobFailed(t); + return null; + } + + // fire listener to alert the original caller that we are done + listener.jobFinished(result); + return result; + } +} diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonJobCoordinator.java b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonJobCoordinator.java new file mode 100644 index 0000000000..9d0ce2cd16 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonJobCoordinator.java @@ -0,0 +1,163 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.python.concurrent; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.raytheon.uf.common.python.PythonInterpreter; + +/** + * Interface to get to the {@link ExecutorService}. Allows multiple thread pools + * to be created in a single JVM, by passing in a different application name. + * + * This class will be used in this way: + * + * + *

+ * 
+ *       AbstractPythonScriptFactory factory = new CAVEPythonFactory();
+ *       PythonJobCoordinator coordinator = PythonJobCoordinator
+ *               .newInstance(factory);
+ *       IPythonExecutor executor = new CAVEExecutor(
+ *               args);
+ *       try {
+ *           coordinator.submitJob(executor, listener);
+ *       } catch (Exception e) {
+ *           e.printStackTrace();
+ *       }
+ * 
+ * }
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 31, 2013            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ +public class PythonJobCoordinator

{ + + private ExecutorService execService = null; + + private ThreadLocal

threadLocal = null; + + private static Map> pools = new ConcurrentHashMap>(); + + private PythonJobCoordinator(final AbstractPythonScriptFactory

factory) { + execService = Executors.newFixedThreadPool(factory.getMaxThreads(), + new PythonThreadFactory(factory.getName())); + threadLocal = new ThreadLocal

() { + protected P initialValue() { + return factory.createPythonScript(); + }; + }; + } + + /** + * Gets the instance by name, or throw a {@link RuntimeException}. + * + * @param name + * @return + */ + public static PythonJobCoordinator getInstance( + String name) { + synchronized (pools) { + if (pools.containsKey(name)) { + return pools.get(name); + } else { + throw new RuntimeException( + "Unable to find instance of PythonJobCoordinator named " + + name + + ", please call newInstance(AbstractPythonScriptFactory)"); + } + } + } + + /** + * Creates a new instance of this class for a new application. If the same + * name already exists, it assumes that it is the same application and + * returns the existing instance. + * + * @param name + * @param numThreads + * @return + */ + public static PythonJobCoordinator newInstance( + AbstractPythonScriptFactory factory) { + synchronized (pools) { + if (pools.containsKey(factory.getName())) { + return (PythonJobCoordinator) pools.get(factory.getName()); + } else { + PythonJobCoordinator pool = new PythonJobCoordinator( + factory); + pools.put(factory.getName(), pool); + return pool; + } + } + } + + /** + * Submits a job to the {@link ExecutorService}. + * + * @param callable + * @return + * @throws Exception + */ + public void submitJob(IPythonExecutor executor, + IPythonJobListener listener, Object... args) throws Exception { + // submit job + PythonJob job = new PythonJob(executor, listener, + threadLocal, args); + execService.submit(job); + } + + /** + * This function should take the {@link PythonInterpreter} on each thread in + * the thread pool and dispose of it and then shutdown the + * {@link ExecutorService} + * + * @param name + */ + public void shutdownCoordinator(String name) { + /* + * TODO need to add for future functionality + */ + } + + /** + * This function should cancel any listeners for a certain task and then + * remove those corresponding tasks off of the queue to be ran. It should + * NOT try to cancel any running python interpreters. + * + * @param name + */ + public void shutdownTask(String name) { + /* + * TODO need to add for future functionality + */ + } +} diff --git a/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonThreadFactory.java b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonThreadFactory.java new file mode 100644 index 0000000000..943c7aa577 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python.concurrent/src/com/raytheon/uf/common/python/concurrent/PythonThreadFactory.java @@ -0,0 +1,71 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.python.concurrent; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Creates new threads named according to what python task they were created + * for. Based nearly identically off of {@link ThreadFactory} + * + *

+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 31, 2013            mnash     Initial creation
+ * 
+ * 
+ * + * @author mnash + * @version 1.0 + */ + +public class PythonThreadFactory implements ThreadFactory { + private static final AtomicInteger poolNumber = new AtomicInteger(1); + + private final ThreadGroup group; + + private final AtomicInteger threadNumber = new AtomicInteger(1); + + private final String namePrefix; + + public PythonThreadFactory(String name) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread() + .getThreadGroup(); + namePrefix = name.toLowerCase() + "-pool-" + + poolNumber.getAndIncrement() + "-thread-"; + } + + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, namePrefix + + threadNumber.getAndIncrement(), 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +}