{"id":2180,"date":"2015-11-29T16:54:42","date_gmt":"2015-11-29T14:54:42","guid":{"rendered":"http:\/\/hasselba.ch\/blog\/?p=2180"},"modified":"2015-11-29T16:56:53","modified_gmt":"2015-11-29T14:56:53","slug":"things-i-never-blogged-about-the-xpagesexecutor-service","status":"publish","type":"post","link":"https:\/\/hasselba.ch\/blog\/?p=2180","title":{"rendered":"Things I never blogged about: The XPagesExecutor Service"},"content":{"rendered":"<p>The XPages engine has its own executor service to run jobs concurrently in another thread: the <em>XPagesExecutor <\/em>service. Under the hood the service uses a <a href=\"https:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/util\/concurrent\/ThreadPoolExecutor.html\" target=\"_blank\">ThreadPoolExecutor<\/a> for executing tasks, so it allows to use <a href=\"https:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/lang\/Runnable.html\" target=\"_blank\">Runnables<\/a> or <a href=\"http:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/util\/concurrent\/Callable.html\" target=\"_blank\">Callables<\/a>\/<a href=\"http:\/\/docs.oracle.com\/javase\/6\/docs\/api\/java\/util\/concurrent\/Future.html\" target=\"_blank\">Futures<\/a> for asynchronous computation. For fun, you can even run a server instance, the started threads can run as long as you want (e.g. they are not bound to the XPages lifecycle).<\/p>\n<p>Here is a small XPage with a button to start a Runnable via the Executor:<\/p>\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;xp:view xmlns:xp=\"http:\/\/www.ibm.com\/xsp\/core\"&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;xp:button\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0value=\"run the job\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0id=\"buttonDoIt\"&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;xp:eventHandler\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0event=\"onclick\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0submit=\"true\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0refreshMode=\"complete\"&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;xp:this.action&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;![CDATA[#{javascript:\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0importPackage(ch.hasselba.xpages);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0new ch.hasselba.xpages.DemoExecutor().doIt();}]]&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/xp:this.action&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/xp:eventHandler&gt;\r\n\u00a0\u00a0 \u00a0&lt;\/xp:button&gt;\r\n\u00a0\u00a0 \u00a0\r\n&lt;\/xp:view&gt;<\/code><\/pre>\n<p>To use the Service, you have to aquire it first, then you can execute a Runnable like in this code snippet:<\/p>\n<pre><code>package ch.hasselba.xpages;\r\n\r\nimport java.util.concurrent.ExecutorService;\r\n\r\nimport lotus.domino.NotesException;\r\nimport lotus.domino.Session;\r\n\r\nimport com.ibm.domino.xsp.module.nsf.NSFComponentModule;\r\nimport com.ibm.domino.xsp.module.nsf.NotesContext;\r\nimport com.ibm.domino.xsp.module.nsf.SessionCloner;\r\nimport com.ibm.xsp.application.XPagesExecutor;\r\n\r\npublic class DemoExecutor {\r\n\u00a0\u00a0 \u00a0private final NSFComponentModule module;\r\n\u00a0\u00a0 \u00a0private final SessionCloner sessionCloner = SessionCloner\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0.getSessionCloner();\r\n\r\n\u00a0\u00a0 \u00a0public DemoExecutor() {\r\n        \/\/ get the current NSFComponentModule\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.module = NotesContext.getCurrent().getModule();\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public void doIt() {\r\n        \/\/ aquire the Executor\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ExecutorService exService = XPagesExecutor.acquire();\r\n        \r\n        \/\/ run the Runnable\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0exService.execute(new DemoRunnable(this.module));\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0class DemoRunnable implements Runnable {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0private final NSFComponentModule module;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0public DemoRunnable(NSFComponentModule module) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.module = module;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0public void run() {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0try {\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ init the NotesThread\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0NotesContext context = new NotesContext(this.module);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0NotesContext.initThread(context);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ now do the job...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0System.out.println(\"Starting the job...\");\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Session session = null;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0try {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ grab the session\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0session = sessionCloner.getSession();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0System.out.println(\"Running as \"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0+ session.getEffectiveUserName());\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Thread.sleep(10000);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (NotesException e) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0e.printStackTrace();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} finally {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0DominoUtils.recycle( session );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0System.out.println(\"Done!\");\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (InterruptedException ie) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ handle interruption here\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} finally {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ kill the Notes thread\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0NotesContext.termThread();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0}\r\n\r\n}<\/code><\/pre>\n<p><a href=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/11\/2015-11-29-08_54_13-SH-Domain-Dev01_Hasselba_CH-IBM-Domino-Administrator.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2182\" src=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/11\/2015-11-29-08_54_13-SH-Domain-Dev01_Hasselba_CH-IBM-Domino-Administrator.png\" alt=\"2015-11-29 08_54_13-SH Domain - Dev01_Hasselba_CH - IBM Domino Administrator\" width=\"660\" height=\"54\" srcset=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/11\/2015-11-29-08_54_13-SH-Domain-Dev01_Hasselba_CH-IBM-Domino-Administrator.png 660w, https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/11\/2015-11-29-08_54_13-SH-Domain-Dev01_Hasselba_CH-IBM-Domino-Administrator-300x25.png 300w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/a><\/p>\n<p>Callables must be submitted instead:<\/p>\n<pre><code>   public long doItWithCallable() {\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ExecutorService exService = XPagesExecutor.acquire();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Future&lt;Long&gt; result = exService.submit(new MyCallable(this.module));\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0long returnValue = (-1);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0try {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0returnValue = result.get();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (InterruptedException ie) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ie.printStackTrace();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (ExecutionException ee) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ee.printStackTrace();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return returnValue;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0class DemoCallable implements Callable {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0private final NSFComponentModule module;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0public DemoCallable(NSFComponentModule module) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.module = module;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0public Long call() throws Exception {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0try {\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ init the NotesThread\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0NotesContext context = new NotesContext(this.module);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0NotesContext.initThread(context);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ now do the job...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0System.out.println(\"Starting the job...\");\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Session session = null;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0try {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ grab the session\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0session = sessionCloner.getSession();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0System.out.println(\"Running as \"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0+ session.getEffectiveUserName());\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Thread.sleep(10000);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (NotesException e) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0e.printStackTrace();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} finally {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0DominoUtils.recycle( session );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0System.out.println(\"Done!\");\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (InterruptedException e) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0e.printStackTrace();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} finally {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ kill the Notes thread\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0NotesContext.termThread();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return System.currentTimeMillis();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0}<\/code><\/pre>\n<p>Hope someone finds it usefull.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The XPages engine has its own executor service to run jobs concurrently in another thread: the XPagesExecutor service. Under the hood the service uses a ThreadPoolExecutor for executing tasks, so it allows to use Runnables or Callables\/Futures for asynchronous computation. &hellip; <a href=\"https:\/\/hasselba.ch\/blog\/?p=2180\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[89,74],"tags":[],"class_list":["post-2180","post","type-post","status-publish","format-standard","hentry","category-java","category-xpages"],"_links":{"self":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2180","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2180"}],"version-history":[{"count":6,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2180\/revisions"}],"predecessor-version":[{"id":2187,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2180\/revisions\/2187"}],"wp:attachment":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2180"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2180"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2180"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}