diff --git a/org.adempiere.base/OSGI-INF/org.adempiere.base.MappedDocumentFactory.xml b/org.adempiere.base/OSGI-INF/org.adempiere.base.MappedDocumentFactory.xml
new file mode 100644
index 0000000000..8d1ace2953
--- /dev/null
+++ b/org.adempiere.base/OSGI-INF/org.adempiere.base.MappedDocumentFactory.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ 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 aae7cf8a49..48bb1afc2d 100644
--- a/org.adempiere.base/src/org/adempiere/base/Core.java
+++ b/org.adempiere.base/src/org/adempiere/base/Core.java
@@ -1002,4 +1002,26 @@ public class Core {
}
return factoryService;
}
+
+ private static IServiceReferenceHolder 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 serviceReference = Service.locator().locate(IMappedDocumentFactory.class).getServiceReference();
+ if (serviceReference != null) {
+ factoryService = serviceReference.getService();
+ s_mappedDocumentFactoryReference = serviceReference;
+ }
+ return factoryService;
+ }
}
diff --git a/org.adempiere.base/src/org/adempiere/base/DefaultDocumentFactory.java b/org.adempiere.base/src/org/adempiere/base/DefaultDocumentFactory.java
index 10f679ccf5..37e1e83ec1 100644
--- a/org.adempiere.base/src/org/adempiere/base/DefaultDocumentFactory.java
+++ b/org.adempiere.base/src/org/adempiere/base/DefaultDocumentFactory.java
@@ -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) {
diff --git a/org.adempiere.base/src/org/adempiere/base/IDocFactory.java b/org.adempiere.base/src/org/adempiere/base/IDocFactory.java
index ca5a90de9a..37b0569ae3 100644
--- a/org.adempiere.base/src/org/adempiere/base/IDocFactory.java
+++ b/org.adempiere.base/src/org/adempiere/base/IDocFactory.java
@@ -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
diff --git a/org.adempiere.base/src/org/adempiere/base/IMappedDocumentFactory.java b/org.adempiere.base/src/org/adempiere/base/IMappedDocumentFactory.java
new file mode 100644
index 0000000000..27cb2cc2c2
--- /dev/null
+++ b/org.adempiere.base/src/org/adempiere/base/IMappedDocumentFactory.java
@@ -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 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.adempiere.base/src/org/adempiere/base/MappedDocumentFactory.java b/org.adempiere.base/src/org/adempiere/base/MappedDocumentFactory.java
new file mode 100644
index 0000000000..0b83da8a53
--- /dev/null
+++ b/org.adempiere.base/src/org/adempiere/base/MappedDocumentFactory.java
@@ -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> 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 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 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());
+ }
+}
diff --git a/org.idempiere.test/src/org/idempiere/test/model/MappedDocumentFactoryTest.java b/org.idempiere.test/src/org/idempiere/test/model/MappedDocumentFactoryTest.java
new file mode 100644
index 0000000000..c50b7355fd
--- /dev/null
+++ b/org.idempiere.test/src/org/idempiere/test/model/MappedDocumentFactoryTest.java
@@ -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);
+ }
+ }
+}