diff --git a/org.adempiere.base/META-INF/MANIFEST.MF b/org.adempiere.base/META-INF/MANIFEST.MF
index 057766f538..1a07bdf726 100644
--- a/org.adempiere.base/META-INF/MANIFEST.MF
+++ b/org.adempiere.base/META-INF/MANIFEST.MF
@@ -51,7 +51,8 @@ Export-Package: bsh,
org.idempiere.cache,
org.idempiere.distributed,
org.idempiere.fa.service.api,
- org.idempiere.model
+ org.idempiere.model,
+ org.idempiere.process
Bundle-RequiredExecutionEnvironment: JavaSE-11
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=11))"
Import-Package: com.google.zxing,
diff --git a/org.adempiere.base/OSGI-INF/org.idempiere.process.MappedProcessFactory.xml b/org.adempiere.base/OSGI-INF/org.idempiere.process.MappedProcessFactory.xml
new file mode 100644
index 0000000000..dc3a95cf5d
--- /dev/null
+++ b/org.adempiere.base/OSGI-INF/org.idempiere.process.MappedProcessFactory.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.adempiere.base/src/org/adempiere/base/Core.java b/org.adempiere.base/src/org/adempiere/base/Core.java
index 6f8c259ade..56517f4067 100644
--- a/org.adempiere.base/src/org/adempiere/base/Core.java
+++ b/org.adempiere.base/src/org/adempiere/base/Core.java
@@ -56,6 +56,7 @@ import org.idempiere.fa.service.api.DepreciationFactoryLookupDTO;
import org.idempiere.fa.service.api.IDepreciationMethod;
import org.idempiere.fa.service.api.IDepreciationMethodFactory;
import org.idempiere.model.IMappedModelFactory;
+import org.idempiere.process.IMappedProcessFactory;
/**
* This is a facade class for the Service Locator.
@@ -945,4 +946,25 @@ public class Core {
}
return modelFactoryService;
}
+
+ private static IServiceReferenceHolder s_mappedProcessFactoryReference = null;
+
+ /**
+ *
+ * @return {@link IMappedProcessFactory}
+ */
+ public static IMappedProcessFactory getMappedProcessFactory(){
+ IMappedProcessFactory processFactoryService = null;
+ if (s_mappedProcessFactoryReference != null) {
+ processFactoryService = s_mappedProcessFactoryReference.getService();
+ if (processFactoryService != null)
+ return processFactoryService;
+ }
+ IServiceReferenceHolder serviceReference = Service.locator().locate(IMappedProcessFactory.class).getServiceReference();
+ if (serviceReference != null) {
+ processFactoryService = serviceReference.getService();
+ s_mappedProcessFactoryReference = serviceReference;
+ }
+ return processFactoryService;
+ }
}
diff --git a/org.adempiere.base/src/org/idempiere/process/IMappedProcessFactory.java b/org.adempiere.base/src/org/idempiere/process/IMappedProcessFactory.java
new file mode 100644
index 0000000000..0486b2cea0
--- /dev/null
+++ b/org.adempiere.base/src/org/idempiere/process/IMappedProcessFactory.java
@@ -0,0 +1,51 @@
+/***********************************************************************
+ * This file is part of iDempiere ERP Open Source *
+ * http://www.idempiere.org *
+ * *
+ * Copyright (C) Contributors *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
+ * MA 02110-1301, USA. *
+ * *
+ * Contributors: *
+ * - hengsin *
+ **********************************************************************/
+package org.idempiere.process;
+
+import java.util.function.Supplier;
+
+import org.compiere.process.ProcessCall;
+
+/**
+ *
+ * @author hengsin
+ *
+ */
+public interface IMappedProcessFactory {
+
+ /**
+ * add name to class mapping
+ * @param name
+ * @param processSupplier
+ */
+ void addMapping(String name, Supplier processSupplier);
+
+ /**
+ * remove name to class mapping
+ * @param name
+ */
+ void removeMapping(String name);
+
+}
\ No newline at end of file
diff --git a/org.adempiere.base/src/org/idempiere/process/MappedProcessFactory.java b/org.adempiere.base/src/org/idempiere/process/MappedProcessFactory.java
new file mode 100644
index 0000000000..e5384f60ba
--- /dev/null
+++ b/org.adempiere.base/src/org/idempiere/process/MappedProcessFactory.java
@@ -0,0 +1,67 @@
+/***********************************************************************
+ * This file is part of iDempiere ERP Open Source *
+ * http://www.idempiere.org *
+ * *
+ * Copyright (C) Contributors *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
+ * MA 02110-1301, USA. *
+ * *
+ * Contributors: *
+ * - hengsin *
+ **********************************************************************/
+package org.idempiere.process;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+import org.adempiere.base.IProcessFactory;
+import org.compiere.process.ProcessCall;
+import org.osgi.service.component.annotations.Component;
+
+/**
+ * @author hengsin
+ *
+ */
+@Component(name = "org.idempiere.process.MappedProcessFactory",
+ immediate = true,
+ service = {IProcessFactory.class, IMappedProcessFactory.class},
+ property = {"service.ranking:Integer=1"})
+public class MappedProcessFactory implements IProcessFactory, IMappedProcessFactory {
+
+ private final ConcurrentHashMap> processMap = new ConcurrentHashMap<>();
+
+ /**
+ * default constructor
+ */
+ public MappedProcessFactory() {
+ }
+
+ @Override
+ public ProcessCall newProcessInstance(String className) {
+ var supplier = processMap.get(className);
+ return supplier != null ? supplier.get() : null;
+ }
+
+ @Override
+ public void addMapping(String name, Supplier processSupplier) {
+ processMap.put(name, processSupplier);
+ }
+
+ @Override
+ public void removeMapping(String name) {
+ processMap.remove(name);
+ }
+}
diff --git a/org.idempiere.test/src/org/idempiere/test/model/MappedProcessFactoryTest.java b/org.idempiere.test/src/org/idempiere/test/model/MappedProcessFactoryTest.java
new file mode 100644
index 0000000000..cad2168c4f
--- /dev/null
+++ b/org.idempiere.test/src/org/idempiere/test/model/MappedProcessFactoryTest.java
@@ -0,0 +1,116 @@
+/***********************************************************************
+ * This file is part of iDempiere ERP Open Source *
+ * http://www.idempiere.org *
+ * *
+ * Copyright (C) Contributors *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
+ * MA 02110-1301, USA. *
+ * *
+ * Contributors: *
+ * - hengsin *
+ **********************************************************************/
+package org.idempiere.test.model;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.adempiere.base.Core;
+import org.adempiere.base.IProcessFactory;
+import org.compiere.process.ProcessCall;
+import org.compiere.process.SvrProcess;
+import org.idempiere.process.IMappedProcessFactory;
+import org.idempiere.process.MappedProcessFactory;
+import org.idempiere.test.AbstractTestCase;
+import org.idempiere.test.TestActivator;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @author hengsin
+ *
+ */
+@TestMethodOrder(OrderAnnotation.class)
+public class MappedProcessFactoryTest extends AbstractTestCase {
+
+ /**
+ * default constructor
+ */
+ public MappedProcessFactoryTest() {
+ }
+
+ @Test
+ @Order(1)
+ public void testDefaultMappedProcessFactory() {
+ IMappedProcessFactory mappedFactory = Core.getMappedProcessFactory();
+ mappedFactory.addMapping(MyTest.class.getName(), () -> new MyTest());
+
+ ProcessCall pc = Core.getProcess(MyTest.class.getName());
+ assertNotNull(pc, "Can't instantiate process class " + MyTest.class.getName());
+ assertTrue(pc instanceof MyTest, "ProcessCall not instanceof " + MyTest.class.getName() + ", it is of type " + pc.getClass().getName());
+ }
+
+ @Test
+ @Order(2)
+ public void testCustomMappedModelFactory() {
+ BundleContext bc = TestActivator.context;
+ Dictionary properties = new Hashtable();
+ properties.put("service.ranking", Integer.valueOf(2));
+ bc.registerService(IProcessFactory.class, new MyFactory(), properties);
+ ProcessCall pc = Core.getProcess(MyTest2.class.getName());
+ assertNotNull(pc, "Can't instantiate process class " + MyTest2.class.getName());
+ assertTrue(pc instanceof MyTest2, "ProcessCall not instanceof " + MyTest2.class.getName() + ", it is of type " + pc.getClass().getName());
+ }
+
+ private final static class MyFactory extends MappedProcessFactory {
+
+ public MyFactory() {
+ addMapping(MyTest2.class.getName(), () -> new MyTest2());
+ }
+
+ }
+
+ private final static class MyTest extends SvrProcess {
+
+ @Override
+ protected void prepare() {
+ }
+
+ @Override
+ protected String doIt() throws Exception {
+ return null;
+ }
+
+ }
+
+ private final static class MyTest2 extends SvrProcess {
+
+ @Override
+ protected void prepare() {
+ }
+
+ @Override
+ protected String doIt() throws Exception {
+ return null;
+ }
+
+ }
+}