IDEMPIERE-4695 Add document factory base class backed by Map and Lambda functional object (#572)

This commit is contained in:
hengsin 2021-02-10 02:17:15 +08:00 committed by GitHub
parent 3a1d53ea4e
commit c159ce5325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 299 additions and 39 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.adempiere.base.MappedDocumentFactory">
<property name="service.ranking" type="Integer" value="1"/>
<property name="gaap" value="*"/>
<service>
<provide interface="org.adempiere.base.IDocFactory"/>
<provide interface="org.adempiere.base.IMappedDocumentFactory"/>
</service>
<implementation class="org.adempiere.base.MappedDocumentFactory"/>
</scr:component>

View File

@ -1002,4 +1002,26 @@ public class Core {
}
return factoryService;
}
private static IServiceReferenceHolder<IMappedDocumentFactory> s_mappedDocumentFactoryReference = null;
/**
*
* @return {@link IMappedDocumentFactory}
*/
public static IMappedDocumentFactory getMappedDocumentFactory() {
IMappedDocumentFactory factoryService = null;
if (s_mappedDocumentFactoryReference != null) {
factoryService = s_mappedDocumentFactoryReference.getService();
if (factoryService != null)
return factoryService;
}
IServiceReferenceHolder<IMappedDocumentFactory> serviceReference = Service.locator().locate(IMappedDocumentFactory.class).getServiceReference();
if (serviceReference != null) {
factoryService = serviceReference.getService();
s_mappedDocumentFactoryReference = serviceReference;
}
return factoryService;
}
}

View File

@ -14,7 +14,6 @@
package org.adempiere.base;
import java.lang.reflect.Constructor;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
@ -23,7 +22,6 @@ import org.compiere.model.MAcctSchema;
import org.compiere.model.MTable;
import org.compiere.util.AdempiereUserError;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
/**
@ -35,42 +33,6 @@ public class DefaultDocumentFactory implements IDocFactory {
private final static CLogger s_log = CLogger.getCLogger(DefaultDocumentFactory.class);
@Override
public Doc getDocument(MAcctSchema as, int AD_Table_ID, int Record_ID,
String trxName) {
String tableName = MTable.getTableName(Env.getCtx(), AD_Table_ID);
//
Doc doc = null;
StringBuilder sql = new StringBuilder("SELECT * FROM ")
.append(tableName)
.append(" WHERE ").append(tableName).append("_ID=? AND Processed='Y'");
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql.toString(), trxName);
pstmt.setInt (1, Record_ID);
rs = pstmt.executeQuery ();
if (rs.next ())
{
doc = getDocument(as, AD_Table_ID, rs, trxName);
}
else
s_log.severe("Not Found: " + tableName + "_ID=" + Record_ID);
}
catch (Exception e)
{
s_log.log (Level.SEVERE, sql.toString(), e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
return doc;
}
@Override
public Doc getDocument(MAcctSchema as, int AD_Table_ID, ResultSet rs,
String trxName) {

View File

@ -13,10 +13,16 @@
*****************************************************************************/
package org.adempiere.base;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import org.compiere.acct.Doc;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MTable;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
/**
*
@ -24,6 +30,7 @@ import org.compiere.model.MAcctSchema;
*
*/
public interface IDocFactory {
/**
* Create Posting document
* @param as accounting schema
@ -32,7 +39,27 @@ public interface IDocFactory {
* @param trxName transaction name
* @return Document or null
*/
public Doc getDocument(MAcctSchema as, int AD_Table_ID, int Record_ID, String trxName);
public default Doc getDocument(MAcctSchema as, int AD_Table_ID, int Record_ID, String trxName) {
String tableName = MTable.getTableName(Env.getCtx(), AD_Table_ID);
//
Doc doc = null;
StringBuilder sql = new StringBuilder("SELECT * FROM ")
.append(tableName)
.append(" WHERE ")
.append(tableName).append("_ID=? AND Processed='Y'");
try (PreparedStatement pstmt = DB.prepareStatement (sql.toString(), trxName);) {
pstmt.setInt (1, Record_ID);
ResultSet rs = pstmt.executeQuery ();
if (rs.next ()) {
doc = getDocument(as, AD_Table_ID, rs, trxName);
}
else
CLogger.getCLogger(getClass()).severe("Not Found: " + tableName + "_ID=" + Record_ID);
} catch (Exception e) {
CLogger.getCLogger(getClass()).log (Level.SEVERE, sql.toString(), e);
}
return doc;
}
/**
* Create Posting document

View File

@ -0,0 +1,71 @@
/***********************************************************************
* 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.adempiere.base;
import java.sql.ResultSet;
import java.util.function.Function;
import org.compiere.acct.Doc;
import org.compiere.model.MAcctSchema;
/**
*
* @author hengsin
*
*/
public interface IMappedDocumentFactory {
/**
* add table name + gaap (optional) to Doc mapping
* @param gaap map to c_acctschema.gaap (optional)
* @param tableName
* @param supplier
*/
public void addMapping(String gaap, String tableName, Function<Parameter, ? extends Doc> supplier);
/**
*
* @param gaap
* @param tableName
*/
public void removeMapping(String gaap, String tableName);
/**
*
* parameter class for doc supplier
*
*/
public final static class Parameter {
public MAcctSchema as;
public ResultSet rs;
public String trxName;
public Parameter(MAcctSchema as, ResultSet rs, String trxName) {
this.as = as;
this.rs = rs;
this.trxName = trxName;
}
}
}

View File

@ -0,0 +1,98 @@
/***********************************************************************
* 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.adempiere.base;
import java.sql.ResultSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.compiere.acct.Doc;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MTable;
import org.compiere.util.Env;
import org.compiere.util.Util;
import org.osgi.service.component.annotations.Component;
@Component(name = "org.adempiere.base.MappedDocumentFactory",
service = {IDocFactory.class, IMappedDocumentFactory.class},
immediate = true,
property = {"service.ranking:Integer=1", "gaap=*"})
/**
*
* Document factory backed by map between tablename + gaap and lambda function object.
* If you create a subclass of this and register it as osgi service, don't register for the IMappedDocumentFactory interface.
* @author hengsin
*
*/
public class MappedDocumentFactory implements IDocFactory, IMappedDocumentFactory {
private final ConcurrentHashMap<String, Function<Parameter, ? extends Doc>> documentMap = new ConcurrentHashMap<>();
/**
* default constructor
*/
public MappedDocumentFactory() {
}
@Override
public Doc getDocument(MAcctSchema as, int AD_Table_ID, ResultSet rs, String trxName) {
String tableName = MTable.getTableName(Env.getCtx(), AD_Table_ID);
String key = tableName + "|" + as.getGAAP();
Function<Parameter, ? extends Doc> function = documentMap.get(key);
if (function != null) {
return function.apply(new Parameter(as, rs, trxName));
}
key = tableName + "|*";
function = documentMap.get(key);
if (function != null) {
return function.apply(new Parameter(as, rs, trxName));
}
return null;
}
@Override
public void addMapping(String gaap, String tableName, Function<Parameter, ? extends Doc> supplier) {
StringBuilder key = new StringBuilder();
key.append(tableName).append("|");
if (Util.isEmpty(gaap, true))
key.append("*");
else
key.append(gaap);
documentMap.put(key.toString(), supplier);
}
@Override
public void removeMapping(String gaap, String tableName) {
StringBuilder key = new StringBuilder();
key.append(tableName).append("|");
if (Util.isEmpty(gaap, true))
key.append("*");
else
key.append(gaap);
documentMap.remove(key.toString());
}
}

View File

@ -0,0 +1,70 @@
/***********************************************************************
* 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 org.adempiere.base.Core;
import org.adempiere.base.IMappedDocumentFactory;
import org.compiere.acct.Doc;
import org.compiere.acct.DocManager;
import org.compiere.acct.Doc_InOut;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MClientInfo;
import org.compiere.model.MInOut;
import org.compiere.util.Env;
import org.idempiere.test.AbstractTestCase;
import org.junit.jupiter.api.Test;
/**
*
* @author hengsin
*
*/
public class MappedDocumentFactoryTest extends AbstractTestCase {
public MappedDocumentFactoryTest() {
}
@Test
public void testDefaultMappedDocumentFactory() {
IMappedDocumentFactory factory = Core.getMappedDocumentFactory();
factory.addMapping(null, MInOut.Table_Name, (p) -> new MyDocInOut(p.as, p.rs, p.trxName));
int C_AcctSchema_ID = MClientInfo.get().getC_AcctSchema1_ID();
MAcctSchema as = new MAcctSchema(Env.getCtx(), C_AcctSchema_ID, getTrxName());
Doc doc = DocManager.getDocument(as, MInOut.Table_ID, 100, getTrxName());
assertTrue(doc != null && doc instanceof MyDocInOut, "Doc not instanceof MyDocInOut. " + (doc == null ? "Doc is Null" : "Doc="+doc.getClass().getName()));
}
private final static class MyDocInOut extends Doc_InOut {
public MyDocInOut(MAcctSchema as, ResultSet rs, String trxName) {
super(as, rs, trxName);
}
}
}