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; + } + + } +}