IDEMPIERE-4675 Add model factory base class backed by Map and Lambda … (#555)

- added interface and default mapped model factory service
- added unit test for default mapped model factory service
This commit is contained in:
hengsin 2021-02-01 22:29:13 +08:00 committed by GitHub
parent 4009c9c8ca
commit 0f263f1c79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 316 additions and 1 deletions

View File

@ -25,6 +25,11 @@
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ds.core.builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>

View File

@ -0,0 +1,8 @@
classpath=true
dsVersion=V1_3
eclipse.preferences.version=1
enabled=true
generateBundleActivationPolicyLazy=true
path=OSGI-INF
validationErrorLevel=error
validationErrorLevel.missingImplicitUnbindMethod=error

View File

@ -90,6 +90,7 @@ Import-Package: com.google.zxing,
org.osgi.framework,
org.osgi.service.cm;version="1.3.0",
org.osgi.service.component;version="1.1.0",
org.osgi.service.component.annotations;version="1.3.0",
org.osgi.service.component.runtime;version="1.3.0",
org.osgi.service.component.runtime.dto;version="1.3.0",
org.osgi.service.event;version="1.2.0",

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.idempiere.model.MappedModelFactory">
<property name="service.ranking" type="Integer" value="1"/>
<service>
<provide interface="org.adempiere.base.IModelFactory"/>
<provide interface="org.idempiere.model.IMappedModelFactory"/>
</service>
<implementation class="org.idempiere.model.MappedModelFactory"/>
</scr:component>

View File

@ -55,6 +55,7 @@ import org.idempiere.distributed.IMessageService;
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;
/**
* This is a facade class for the Service Locator.
@ -924,4 +925,24 @@ public class Core {
return ids;
}
private static IServiceReferenceHolder<IMappedModelFactory> s_mappedModelFactoryReference = null;
/**
*
* @return {@link IMappedModelFactory}
*/
public static IMappedModelFactory getMappedModelFactory(){
IMappedModelFactory modelFactoryService = null;
if (s_mappedModelFactoryReference != null) {
modelFactoryService = s_mappedModelFactoryReference.getService();
if (modelFactoryService != null)
return modelFactoryService;
}
IServiceReferenceHolder<IMappedModelFactory> serviceReference = Service.locator().locate(IMappedModelFactory.class).getServiceReference();
if (serviceReference != null) {
modelFactoryService = serviceReference.getService();
s_mappedModelFactoryReference = serviceReference;
}
return modelFactoryService;
}
}

View File

@ -0,0 +1,57 @@
/***********************************************************************
* 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.model;
import java.sql.ResultSet;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.compiere.model.PO;
/**
*
* @author hengsin
*
*/
public interface IMappedModelFactory {
/**
* add table name to class mapping
* @param tableName
* @param classSupplier
* @param recordIdFunction
* @param resultSetFunction
*/
void addMapping(String tableName, Supplier<Class<?>> classSupplier,
BiFunction<Integer, String, ? extends PO> recordIdFunction,
BiFunction<ResultSet, String, ? extends PO> resultSetFunction);
/**
* remove table name to class mapping
* @param tableName
*/
void removeMapping(String tableName);
}

View File

@ -0,0 +1,88 @@
/***********************************************************************
* 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.model;
import java.sql.ResultSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.adempiere.base.IModelFactory;
import org.compiere.model.PO;
import org.osgi.service.component.annotations.Component;
/**
* @author hengsin
*
*/
@Component(name = "org.idempiere.model.MappedModelFactory",
immediate = true,
service = {IModelFactory.class, IMappedModelFactory.class},
property = {"service.ranking:Integer=1"})
public class MappedModelFactory implements IModelFactory, IMappedModelFactory {
private final ConcurrentHashMap<String, Supplier<Class<?>>> classMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, BiFunction<Integer, String, ? extends PO>> recordIdMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, BiFunction<ResultSet, String, ? extends PO>> resultSetMap = new ConcurrentHashMap<>();
/**
* default constructor
*/
public MappedModelFactory() {
}
@Override
public Class<?> getClass(String tableName) {
var supplier = classMap.get(tableName);
return supplier != null ? supplier.get() : null;
}
@Override
public PO getPO(String tableName, int Record_ID, String trxName) {
var function = recordIdMap.get(tableName);
return function != null ? function.apply(Record_ID, trxName) : null;
}
@Override
public PO getPO(String tableName, ResultSet rs, String trxName) {
var function = resultSetMap.get(tableName);
return function != null ? function.apply(rs, trxName) : null;
}
@Override
public void addMapping(String tableName, Supplier<Class<?>> classSupplier, BiFunction<Integer, String, ? extends PO> recordIdFunction,
BiFunction<ResultSet, String, ? extends PO> resultSetFunction) {
classMap.put(tableName, classSupplier);
recordIdMap.put(tableName, recordIdFunction);
resultSetMap.put(tableName, resultSetFunction);
}
@Override
public void removeMapping(String tableName) {
classMap.remove(tableName);
recordIdMap.remove(tableName);
resultSetMap.remove(tableName);
}
}

View File

@ -0,0 +1,126 @@
/***********************************************************************
* 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.assertTrue;
import java.sql.ResultSet;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Properties;
import org.adempiere.base.Core;
import org.adempiere.base.IModelFactory;
import org.compiere.model.MTable;
import org.compiere.model.PO;
import org.compiere.model.X_Test;
import org.compiere.util.CacheMgt;
import org.compiere.util.Env;
import org.idempiere.model.IMappedModelFactory;
import org.idempiere.model.MappedModelFactory;
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 MappedModelFactoryTest extends AbstractTestCase {
/**
*
*/
public MappedModelFactoryTest() {
}
@Test
@Order(1)
public void testDefaultMappedModelFactory() {
IMappedModelFactory mappedFactory = Core.getMappedModelFactory();
mappedFactory.addMapping(MyTest.Table_Name, () -> MyTest.class, (id, trxName) -> new MyTest(Env.getCtx(), id, trxName),
(rs, trxName) -> new MyTest(Env.getCtx(), rs, trxName));
PO po = MTable.get(MyTest.Table_ID).getPO(0, getTrxName());
assertTrue(po instanceof MyTest, "PO not instanceof MyTest. PO.className="+po.getClass().getName());
}
@Test
@Order(2)
public void testCustomMappedModelFactory() {
BundleContext bc = TestActivator.context;
Dictionary<String, Object> properties = new Hashtable<String, Object>();
properties.put("service.ranking", Integer.valueOf(2));
bc.registerService(IModelFactory.class, new MyFactory(), properties);
CacheMgt.get().reset();
PO po = MTable.get(MyTest2.Table_ID).getPO(0, getTrxName());
assertTrue(po instanceof MyTest2, "PO not instanceof MyTest2. PO.className="+po.getClass().getName());
}
private final static class MyFactory extends MappedModelFactory {
public MyFactory() {
addMapping(MyTest2.Table_Name, () -> MyTest2.class, (id, trxName) -> new MyTest2(Env.getCtx(), id, trxName),
(rs, trxName) -> new MyTest2(Env.getCtx(), rs, trxName));
}
}
private final static class MyTest extends X_Test {
/**
*
*/
private static final long serialVersionUID = 2010413233032792416L;
public MyTest(Properties ctx, int Test_ID, String trxName) {
super(ctx, Test_ID, trxName);
}
public MyTest(Properties ctx, ResultSet rs, String trxName) {
super(ctx, rs, trxName);
}
}
private final static class MyTest2 extends X_Test {
/**
*
*/
private static final long serialVersionUID = 2010413233032792416L;
public MyTest2(Properties ctx, int Test_ID, String trxName) {
super(ctx, Test_ID, trxName);
}
public MyTest2(Properties ctx, ResultSet rs, String trxName) {
super(ctx, rs, trxName);
}
}
}