From 954b3b2fec68d95527abdd05bab88cfc3e4b7234 Mon Sep 17 00:00:00 2001 From: Carlos Ruiz Date: Sat, 26 Aug 2023 03:49:39 +0200 Subject: [PATCH] IDEMPIERE-5567 Support of UUID as Key (FHCA-4195) (#1976) - Fix 2Pack to work with UUID based tables - Implement ability for PackOut/PackIn multi ID columns --- .../src/org/compiere/model/GridField.java | 2 +- .../src/org/compiere/model/MColumn.java | 4 +- .../src/org/compiere/util/DisplayType.java | 25 ++- .../src/org/idempiere/process/MoveClient.java | 5 +- .../handler/GenericPOElementHandler.java | 15 +- .../handler/IndexColumnElementHandler.java | 4 +- .../pipo2/handler/MenuElementHandler.java | 2 +- .../handler/ReferenceTableElementHandler.java | 4 +- .../handler/ViewColumnElementHandler.java | 2 +- .../pipo2/handler/WorkflowElementHandler.java | 2 +- .../pipo2/AbstractElementHandler.java | 2 +- .../src/org/adempiere/pipo2/IDFinder.java | 180 ++++++++++++------ .../src/org/adempiere/pipo2/POFinder.java | 4 +- .../org/adempiere/pipo2/PackRollProcess.java | 2 +- .../src/org/adempiere/pipo2/PoExporter.java | 56 ++++-- .../src/org/adempiere/pipo2/PoFiller.java | 110 +++++++---- .../org/adempiere/pipo2/ReferenceUtils.java | 112 ++++++++++- 17 files changed, 391 insertions(+), 140 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/model/GridField.java b/org.adempiere.base/src/org/compiere/model/GridField.java index 09ae67d48f..eac984b1be 100644 --- a/org.adempiere.base/src/org/compiere/model/GridField.java +++ b/org.adempiere.base/src/org/compiere/model/GridField.java @@ -1152,7 +1152,7 @@ public class GridField } if (allValid) return true; - } else if (getDisplayType() == DisplayType.ChosenMultipleSelectionTable || getDisplayType() == DisplayType.ChosenMultipleSelectionSearch) { + } else if (DisplayType.isMultiID(getDisplayType())) { boolean allValid = true; for (String vals : ((String)m_value).split(",")) { Integer vali = Integer.valueOf(vals); diff --git a/org.adempiere.base/src/org/compiere/model/MColumn.java b/org.adempiere.base/src/org/compiere/model/MColumn.java index 4fd6eda867..9f8ffa1811 100644 --- a/org.adempiere.base/src/org/compiere/model/MColumn.java +++ b/org.adempiere.base/src/org/compiere/model/MColumn.java @@ -792,7 +792,9 @@ public class MColumn extends X_AD_Column implements ImmutablePOSupport if (foreignTableMulti != null) return foreignTableMulti; int refid = getAD_Reference_ID(); - if (DisplayType.ChosenMultipleSelectionTable == refid || DisplayType.ChosenMultipleSelectionSearch == refid) { + if (DisplayType.ChosenMultipleSelectionList == refid) { + foreignTableMulti = "AD_Ref_List"; + } else if (DisplayType.ChosenMultipleSelectionTable == refid || DisplayType.ChosenMultipleSelectionSearch == refid) { foreignTableMulti = DB.getSQLValueStringEx(get_TrxName(), sqlTableNameReference, getAD_Column_ID()); } else if (DisplayType.SingleSelectionGrid == refid || DisplayType.MultipleSelectionGrid == refid) { foreignTableMulti = DB.getSQLValueStringEx(get_TrxName(), sqlTableNameSelectionGrid, getAD_Column_ID()); diff --git a/org.adempiere.base/src/org/compiere/util/DisplayType.java b/org.adempiere.base/src/org/compiere/util/DisplayType.java index 85cdbb9fa0..18f7dc2fea 100644 --- a/org.adempiere.base/src/org/compiere/util/DisplayType.java +++ b/org.adempiere.base/src/org/compiere/util/DisplayType.java @@ -548,7 +548,9 @@ public final class DisplayType || displayType == RadiogroupList || displayType == ChosenMultipleSelectionTable || displayType == ChosenMultipleSelectionSearch - || displayType == ChosenMultipleSelectionList) + || displayType == ChosenMultipleSelectionList + || displayType == SingleSelectionGrid + || displayType == MultipleSelectionGrid) return true; //not custom type, don't have to check factory @@ -638,11 +640,22 @@ public final class DisplayType */ public static boolean isChosenMultipleSelection(int displayType) { - if (displayType == ChosenMultipleSelectionList || displayType == ChosenMultipleSelectionSearch - || displayType == ChosenMultipleSelectionTable) - return true; - else - return false; + return ( displayType == ChosenMultipleSelectionList + || displayType == ChosenMultipleSelectionSearch + || displayType == ChosenMultipleSelectionTable); + } + + /** + * + * @param displayType + * @return true if displayType is a multi ID string separated by commas + */ + public static boolean isMultiID(int displayType) + { + return ( displayType == ChosenMultipleSelectionSearch + || displayType == ChosenMultipleSelectionTable + || displayType == SingleSelectionGrid + || displayType == MultipleSelectionGrid); } /************************************************************************** diff --git a/org.adempiere.base/src/org/idempiere/process/MoveClient.java b/org.adempiere.base/src/org/idempiere/process/MoveClient.java index 0a045651aa..3aa7276122 100644 --- a/org.adempiere.base/src/org/idempiere/process/MoveClient.java +++ b/org.adempiere.base/src/org/idempiere/process/MoveClient.java @@ -907,10 +907,7 @@ public class MoveClient extends SvrProcess { String convertTable = column.getReferenceTableName(); if ((tableName + "_ID").equalsIgnoreCase(columnName)) { convertTable = tableName; - } else if ( column.getAD_Reference_ID() == DisplayType.ChosenMultipleSelectionTable - || column.getAD_Reference_ID() == DisplayType.ChosenMultipleSelectionSearch - || column.getAD_Reference_ID() == DisplayType.SingleSelectionGrid - || column.getAD_Reference_ID() == DisplayType.MultipleSelectionGrid) { + } else if (DisplayType.isMultiID(column.getAD_Reference_ID())) { convertTable = column.getMultiReferenceTableName(); } else if (convertTable != null && ("AD_Ref_List".equalsIgnoreCase(convertTable) diff --git a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/GenericPOElementHandler.java b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/GenericPOElementHandler.java index cf3a961028..ec53cd6acf 100644 --- a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/GenericPOElementHandler.java +++ b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/GenericPOElementHandler.java @@ -173,7 +173,7 @@ public class GenericPOElementHandler extends AbstractElementHandler { if (createElement) { // - if (po.get_KeyColumns() != null && po.get_KeyColumns().length == 1 && po.get_ID() > 0 + if (po.get_KeyColumns() != null && po.get_KeyColumns().length == 1 && (po.get_ID() > 0 || po.get_UUID() != null) && ! IHandlerRegistry.TABLE_GENERIC_SINGLE_HANDLER.equals(ctx.packOut.getCurrentPackoutItem().getType())) { ElementHandler handler = ctx.packOut.getHandler(po.get_TableName()); if (handler != null && !handler.getClass().equals(this.getClass()) ) { @@ -220,13 +220,22 @@ public class GenericPOElementHandler extends AbstractElementHandler { private void exportDetail(PIPOContext ctx, TransformerHandler document, GenericPO parent, String[] tables) { String mainTable = tables[0]; AttributesImpl atts = new AttributesImpl(); - String sql = "SELECT * FROM " + mainTable + " WHERE " + parent.get_TableName() + "_ID = ?"; + String keyColumn; + MTable table = MTable.get(ctx.ctx, parent.get_TableName()); + if (table.isUUIDKeyTable()) + keyColumn = PO.getUUIDColumnName(parent.get_TableName()); + else + keyColumn = parent.get_TableName() + "_ID"; + String sql = "SELECT * FROM " + mainTable + " WHERE " + keyColumn + " = ?"; PreparedStatement pstmt = null; ResultSet rs = null; try { sql = MRole.getDefault().addAccessSQL(sql, mainTable, true, true); pstmt = DB.prepareStatement(sql, null); - pstmt.setInt(1, parent.get_ID()); + if (table.isUUIDKeyTable()) + pstmt.setString(1, parent.get_UUID()); + else + pstmt.setInt(1, parent.get_ID()); rs = pstmt.executeQuery(); while (rs.next()) { GenericPO po = new GenericPO(mainTable, ctx.ctx, rs, getTrxName(ctx)); diff --git a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/IndexColumnElementHandler.java b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/IndexColumnElementHandler.java index badc78c894..1f5fb562b8 100644 --- a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/IndexColumnElementHandler.java +++ b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/IndexColumnElementHandler.java @@ -58,7 +58,7 @@ public class IndexColumnElementHandler extends AbstractElementHandler { parentId = getParentId(element, MTableIndex.Table_Name); } else { Element pfElement = element.properties.get(MIndexColumn.COLUMNNAME_AD_TableIndex_ID); - parentId = ReferenceUtils.resolveReference(ctx.ctx, pfElement, getTrxName(ctx)); + parentId = ReferenceUtils.resolveReferenceAsInt(ctx.ctx, pfElement, getTrxName(ctx)); } if (parentId <= 0) { element.defer = true; @@ -80,7 +80,7 @@ public class IndexColumnElementHandler extends AbstractElementHandler { int columnId = 0; Element columnElement = element.properties.get("AD_Column_ID"); if (ReferenceUtils.isIDLookup(columnElement) || ReferenceUtils.isUUIDLookup(columnElement)) { - columnId = ReferenceUtils.resolveReference(ctx.ctx, columnElement, getTrxName(ctx)); + columnId = ReferenceUtils.resolveReferenceAsInt(ctx.ctx, columnElement, getTrxName(ctx)); } if (columnId > 0) mIndexColumn.setAD_Column_ID(columnId); diff --git a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/MenuElementHandler.java b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/MenuElementHandler.java index 129cc891a0..498557cd73 100644 --- a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/MenuElementHandler.java +++ b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/MenuElementHandler.java @@ -103,7 +103,7 @@ public class MenuElementHandler extends AbstractElementHandler { Element parentElement = element.properties.get("Parent_ID"); int parentId = 0; if (parentElement != null) { - parentId = ReferenceUtils.resolveReference(ctx.ctx, parentElement, getTrxName(ctx)); + parentId = ReferenceUtils.resolveReferenceAsInt(ctx.ctx, parentElement, getTrxName(ctx)); } String strSeqNo = getStringValue(element, "SeqNo"); diff --git a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ReferenceTableElementHandler.java b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ReferenceTableElementHandler.java index e69a33285d..490c692d0d 100644 --- a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ReferenceTableElementHandler.java +++ b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ReferenceTableElementHandler.java @@ -65,12 +65,12 @@ public class ReferenceTableElementHandler extends AbstractElementHandler { return; } Element displayElement = element.properties.get("AD_Display"); - int displayColumnId = ReferenceUtils.resolveReference(ctx.ctx, displayElement, getTrxName(ctx)); + int displayColumnId = ReferenceUtils.resolveReferenceAsInt(ctx.ctx, displayElement, getTrxName(ctx)); refTable.setAD_Display(displayColumnId); Element keyElement = element.properties.get("AD_Key"); - int keyColumnId = ReferenceUtils.resolveReference(ctx.ctx, keyElement, getTrxName(ctx)); + int keyColumnId = ReferenceUtils.resolveReferenceAsInt(ctx.ctx, keyElement, getTrxName(ctx)); refTable.setAD_Key(keyColumnId); if (refTable.is_new() || refTable.is_Changed()) { diff --git a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ViewColumnElementHandler.java b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ViewColumnElementHandler.java index fb8c998623..afc6219903 100644 --- a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ViewColumnElementHandler.java +++ b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/ViewColumnElementHandler.java @@ -58,7 +58,7 @@ public class ViewColumnElementHandler extends AbstractElementHandler { parentId = getParentId(element, MViewComponent.Table_Name); } else { Element pfElement = element.properties.get(MViewColumn.COLUMNNAME_AD_ViewComponent_ID); - parentId = ReferenceUtils.resolveReference(ctx.ctx, pfElement, getTrxName(ctx)); + parentId = ReferenceUtils.resolveReferenceAsInt(ctx.ctx, pfElement, getTrxName(ctx)); } if (parentId <= 0) { element.defer = true; diff --git a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/WorkflowElementHandler.java b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/WorkflowElementHandler.java index 8e0bbf14ac..95b3ecda24 100644 --- a/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/WorkflowElementHandler.java +++ b/org.adempiere.pipo.handlers/src/org/adempiere/pipo2/handler/WorkflowElementHandler.java @@ -116,7 +116,7 @@ public class WorkflowElementHandler extends AbstractElementHandler { if (value != null && value.trim().length() > 0) { MWorkflow m_Workflow = new MWorkflow(ctx.ctx, element.recordId, getTrxName(ctx)); PoFiller filler = new PoFiller(ctx, m_Workflow, element, this); - int id = filler.setTableReference("AD_WF_Node_ID"); + int id = ((Number)filler.setTableReference("AD_WF_Node_ID")).intValue(); if (id <= 0) { log.warning("Failed to resolve start node reference for workflow element. Workflow=" + m_Workflow.getName() + " StartNode=" + value); diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/AbstractElementHandler.java b/org.adempiere.pipo/src/org/adempiere/pipo2/AbstractElementHandler.java index 6c1ba7c1ba..1efe0cdd7e 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/AbstractElementHandler.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/AbstractElementHandler.java @@ -141,7 +141,7 @@ public abstract class AbstractElementHandler implements ElementHandler { public void backupRecord(PIPOContext ctx, int AD_Package_Imp_Detail_ID, String tableName,PO from){ // Create new record - MTable mTable = MTable.get(ctx.ctx, tableName); + MTable mTable = MTable.get(ctx.ctx, tableName, getTrxName(ctx)); int tableID = mTable.getAD_Table_ID(); POInfo poInfo = POInfo.getPOInfo(ctx.ctx, tableID); diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/IDFinder.java b/org.adempiere.pipo/src/org/adempiere/pipo2/IDFinder.java index 2802f50781..a6e1421f53 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/IDFinder.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/IDFinder.java @@ -32,6 +32,7 @@ import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.compiere.model.MColumn; import org.compiere.model.MTable; +import org.compiere.model.PO; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.DisplayType; @@ -46,7 +47,7 @@ public class IDFinder { private static final CLogger log = CLogger.getCLogger(IDFinder.class); - private static MapidCache = new ConcurrentHashMap(); + private static MapidCache = new ConcurrentHashMap(); /** * Get ID from column value for a table. @@ -58,11 +59,9 @@ public class IDFinder { * @param trxName * @return */ - public static int findIdByColumn (String tableName, String columnName, Object value, int AD_Client_ID, boolean ignorecase, String trxName) { + public static Object findIdByColumn (String tableName, String columnName, Object value, int AD_Client_ID, boolean ignorecase, String trxName) { if (value == null) - return 0; - - int id = -1; + return null; //construct cache key StringBuilder key = new StringBuilder(); @@ -77,9 +76,18 @@ public class IDFinder { if (idCache.containsKey(key.toString())) return idCache.get(key.toString()); + Object id = null; + + MTable table = MTable.get(Env.getCtx(), tableName, trxName); + String keycol; + if (table.isUUIDKeyTable()) + keycol = PO.getUUIDColumnName(tableName); + else + keycol = tableName + "_ID"; + StringBuilder sqlB = new StringBuilder ("SELECT ") - .append(tableName) - .append("_ID FROM ") + .append(keycol) + .append(" FROM ") .append(tableName) .append(" WHERE ") .append(" AD_Client_ID IN (0, ?) AND "); @@ -124,11 +132,9 @@ public class IDFinder { columns = new String[]{columnName}; } - sqlB.append(" Order By AD_Client_ID Desc, ") - .append(tableName) - .append("_ID"); + sqlB.append(" ORDER BY AD_Client_ID DESC, ") + .append(keycol); - MTable table = MTable.get(Env.getCtx(), tableName); PreparedStatement pstmt = null; ResultSet rs = null; try { @@ -159,8 +165,12 @@ public class IDFinder { } rs = pstmt.executeQuery(); - if (rs.next()) - id = rs.getInt(1); + if (rs.next()) { + if (table.isUUIDKeyTable()) + id = rs.getString(1); + else + id = rs.getInt(1); + } } catch (Exception e) { throw new DatabaseAccessException(e); @@ -169,13 +179,13 @@ public class IDFinder { } //update cache - if (id >= 0) + if (id != null) idCache.put(key.toString(), id); return id; } - public static int findIdByColumn(String tableName, String columnName, Object value, int clientId, String trxName) { + public static Object findIdByColumn(String tableName, String columnName, Object value, int clientId, String trxName) { return findIdByColumn(tableName, columnName, value, clientId, false, trxName); } @@ -188,8 +198,7 @@ public class IDFinder { * @param nameMaster * @param trxName */ - public static int findIdByNameAndParentName (String tableName, String name, String tableNameMaster, String nameMaster, int AD_Client_ID, String trxName) { - int id = 0; + public static Object findIdByNameAndParentName (String tableName, String name, String tableNameMaster, String nameMaster, int AD_Client_ID, String trxName) { //construct cache key StringBuilder key = new StringBuilder(); key.append(tableName) @@ -204,22 +213,35 @@ public class IDFinder { if (idCache.containsKey(key.toString())) return idCache.get(key.toString()); + Object id = null; + MTable tableMaster = MTable.get(Env.getCtx(), tableNameMaster, trxName); + String keycolMaster; + if (tableMaster.isUUIDKeyTable()) + keycolMaster = PO.getUUIDColumnName(tableNameMaster); + else + keycolMaster = tableNameMaster + "_ID"; StringBuilder parentSql = new StringBuilder("SELECT ") - .append(tableNameMaster) - .append("_ID FROM ") + .append(keycolMaster) + .append(" FROM ") .append(tableNameMaster) .append(" WHERE Name = ? AND AD_Client_ID IN (0, ?) ") .append("ORDER BY AD_Client_ID Desc"); - int parentId = DB.getSQLValue(trxName, parentSql.toString(), name, Env.getAD_Client_ID(Env.getCtx())); + Object parentId = DB.getSQLValueEx(trxName, parentSql.toString(), name, Env.getAD_Client_ID(Env.getCtx())); - if (parentId > 0) { + if (parentId != null) { + MTable table = MTable.get(Env.getCtx(), tableName, trxName); + String keycol; + if (table.isUUIDKeyTable()) + keycol = PO.getUUIDColumnName(tableName); + else + keycol = tableNameMaster + "_ID"; StringBuilder sqlB = new StringBuilder ("SELECT ") - .append(tableName) - .append("_ID FROM ") + .append(keycol) + .append(" FROM ") .append(tableName) .append(" WHERE Name = ? AND ") - .append(tableNameMaster) - .append("_ID = ?"); + .append(keycol) + .append(" = ?"); PreparedStatement pstmt = null; ResultSet rs = null; @@ -227,7 +249,10 @@ public class IDFinder { pstmt = DB.prepareStatement(sqlB.toString(), trxName); pstmt.setString(1, name); pstmt.setString(2, nameMaster); - pstmt.setInt(3, parentId); + if (table.isUUIDKeyTable()) + pstmt.setString(3, (String)parentId); + else + pstmt.setInt(3, ((Number)parentId).intValue()); rs = pstmt.executeQuery(); if (rs.next()) id = rs.getInt(1); @@ -239,7 +264,7 @@ public class IDFinder { } //update cache - if (id > 0) + if (id != null) idCache.put(key.toString(), id); return id; @@ -257,7 +282,7 @@ public class IDFinder { * @param trxName * @return */ - public static int findIdByColumnAndParentId (String tableName, String columnName, String name, String tableNameMaster, int masterID, int AD_Client_ID, String trxName) { + public static Object findIdByColumnAndParentId (String tableName, String columnName, String name, String tableNameMaster, Object masterID, int AD_Client_ID, String trxName) { return findIdByColumnAndParentId(tableName, columnName, name, tableNameMaster, masterID, AD_Client_ID, false, trxName); } @@ -271,29 +296,41 @@ public class IDFinder { * @param trxName */ - public static int findIdByColumnAndParentId (String tableName, String columnName, String name, String tableNameMaster, int masterID, int AD_Client_ID, boolean ignoreCase, String trxName) { - int id = 0; - + public static Object findIdByColumnAndParentId (String tableName, String columnName, String name, String tableNameMaster, Object masterID, int AD_Client_ID, boolean ignoreCase, String trxName) { //check cache String key = tableName + "." + columnName + "=" + name + tableNameMaster + "=" + masterID; if (idCache.containsKey(key)) return idCache.get(key); + Object id = null; + + MTable table = MTable.get(Env.getCtx(), tableName, trxName); + String keycol; + if (table.isUUIDKeyTable()) + keycol = PO.getUUIDColumnName(tableName); + else + keycol = tableName + "_ID"; + MTable tableMaster = MTable.get(Env.getCtx(), tableNameMaster, trxName); + String keycolMaster; + if (tableMaster.isUUIDKeyTable()) + keycolMaster = PO.getUUIDColumnName(tableNameMaster); + else + keycolMaster = tableNameMaster + "_ID"; StringBuilder sqlB = new StringBuilder ("SELECT ") - .append(tableName) - .append("_ID FROM ") + .append(keycol) + .append(" FROM ") .append(tableName) .append(" WHERE "); if (ignoreCase) { - sqlB.append("Upper(") + sqlB.append("UPPER(") .append(columnName) - .append(") = ? and "); + .append(") = ? AND "); } else { sqlB.append(columnName) - .append(" = ? and "); + .append(" = ? AND "); } - sqlB.append(tableNameMaster+"_ID = ? AND AD_Client_ID IN (0, ?) ") + sqlB.append(keycolMaster+" = ? AND AD_Client_ID IN (0, ?) ") .append("ORDER BY AD_Client_ID Desc "); if (log.isLoggable(Level.INFO)) log.info(sqlB.toString()); @@ -308,12 +345,15 @@ public class IDFinder { } else { pstmt.setString(1, name); } - pstmt.setInt(2, masterID); + if (tableMaster.isUUIDKeyTable()) + pstmt.setString(2, (String)masterID); + else + pstmt.setInt(2, ((Number)masterID).intValue()); pstmt.setInt(3, AD_Client_ID); rs = pstmt.executeQuery(); if (rs.next()) { - id = rs.getInt(1); + id = rs.getObject(1); } } catch (Exception e) { @@ -323,7 +363,7 @@ public class IDFinder { } //update cache - if (id > 0) + if (id != null) idCache.put(key, id); return id; @@ -338,9 +378,7 @@ public class IDFinder { * @param masterID * @param trxName */ - public static int findIdByNameAndParentId (String tableName, String name, String tableNameMaster, int masterID, int AD_Client_ID, String trxName) { - int id = 0; - + public static Object findIdByNameAndParentId (String tableName, String name, String tableNameMaster, Object masterID, int AD_Client_ID, String trxName) { //construct cache key StringBuilder key = new StringBuilder(); key.append(tableName) @@ -357,25 +395,41 @@ public class IDFinder { if (idCache.containsKey(key.toString())) return idCache.get(key.toString()); + Object id = null; + MTable table = MTable.get(Env.getCtx(), tableName, trxName); + String keycol; + if (table.isUUIDKeyTable()) + keycol = PO.getUUIDColumnName(tableName); + else + keycol = tableName + "_ID"; + MTable tableMaster = MTable.get(Env.getCtx(), tableNameMaster, trxName); + String keycolMaster; + if (tableMaster.isUUIDKeyTable()) + keycolMaster = PO.getUUIDColumnName(tableNameMaster); + else + keycolMaster = tableNameMaster + "_ID"; StringBuilder sqlB = new StringBuilder ("SELECT ") - .append(tableName) - .append("_ID FROM ") + .append(keycol) + .append(" FROM ") .append(tableName) .append(" WHERE Name=? AND ") - .append(tableNameMaster) - .append("_ID=? AND AD_Client_ID IN (0, ?) ") - .append("ORDER BY AD_Client_ID Desc"); + .append(keycolMaster) + .append("=? AND AD_Client_ID IN (0, ?) ") + .append("ORDER BY AD_Client_ID DESC"); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sqlB.toString(), trxName); pstmt.setString(1, name); - pstmt.setInt(2, masterID); + if (tableMaster.isUUIDKeyTable()) + pstmt.setString(2, (String)masterID); + else + pstmt.setInt(2, ((Number)masterID).intValue()); pstmt.setInt(3, AD_Client_ID); rs = pstmt.executeQuery(); if (rs.next()) - id = rs.getInt(1); + id = rs.getObject(1); } catch (Exception e) { throw new DatabaseAccessException(e); @@ -384,7 +438,7 @@ public class IDFinder { } //update cache - if (id > 0) + if (id != null) idCache.put(key.toString(), id); return id; @@ -398,9 +452,7 @@ public class IDFinder { * @param AD_Client_ID * @param trxName */ - public static int findIdByName (String tableName, String name, int AD_Client_ID, String trxName) { - int id = 0; - + public static Object findIdByName (String tableName, String name, int AD_Client_ID, String trxName) { //construct cache key StringBuilder key = new StringBuilder(); key.append(tableName) @@ -413,13 +465,19 @@ public class IDFinder { if (idCache.containsKey(key.toString())) return idCache.get(key.toString()); + Object id = null; + MTable table = MTable.get(Env.getCtx(), tableName, trxName); + String keycol; + if (table.isUUIDKeyTable()) + keycol = PO.getUUIDColumnName(tableName); + else + keycol = tableName + "_ID"; + StringBuilder sql = new StringBuilder("SELECT ") + .append(keycol) + .append(" FROM ") .append(tableName) - .append("_ID ") - .append("FROM ") - .append(tableName) - .append(" ") - .append("WHERE Name=? ") + .append(" WHERE Name=? ") .append(" AND AD_Client_ID IN (0, ?) ") .append(" ORDER BY AD_Client_ID Desc"); @@ -431,7 +489,7 @@ public class IDFinder { pstmt.setInt(2, AD_Client_ID); rs = pstmt.executeQuery(); if (rs.next()) - id = rs.getInt(1); + id = rs.getObject(1); } catch (Exception e) { throw new DatabaseAccessException(e); @@ -440,7 +498,7 @@ public class IDFinder { } //update cache - if (id > 0) + if (id != null) idCache.put(key.toString(), id); return id; diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/POFinder.java b/org.adempiere.pipo/src/org/adempiere/pipo2/POFinder.java index cdec49b919..fcef3e6f89 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/POFinder.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/POFinder.java @@ -47,7 +47,7 @@ public class POFinder { int AD_Client_ID = Env.getAD_Client_ID(ctx); if (AD_Client_ID==0) return uuid; - MTable table = MTable.get(ctx, tableName); + MTable table = MTable.get(ctx, tableName, trxName); if (table == null) { throw new IllegalStateException("getTargetUUID couldn't find table named " + tableName); } @@ -64,7 +64,7 @@ public class POFinder { */ public static void updateUUIDMap(PIPOContext ctx, String tableName, String uuid, String targetUUID) { X_AD_Package_UUID_Map map = new X_AD_Package_UUID_Map(ctx.ctx, 0, ctx.trx.getTrxName()); - MTable table = MTable.get(ctx.ctx, tableName); + MTable table = MTable.get(ctx.ctx, tableName, ctx.trx.getTrxName()); map.setAD_Table_ID(table.getAD_Table_ID()); map.setSource_UUID(uuid); map.setTarget_UUID(targetUUID); diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/PackRollProcess.java b/org.adempiere.pipo/src/org/adempiere/pipo2/PackRollProcess.java index 9f3ec7d89d..db6402360f 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/PackRollProcess.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/PackRollProcess.java @@ -137,7 +137,7 @@ public class PackRollProcess extends SvrProcess { DB.close(rs, pstmt); } // Get Table value - tableName = MTable.getTableName(getCtx(), backup.getAD_Table_ID()); + tableName = MTable.get(getCtx(), backup.getAD_Table_ID(), get_TrxName()).getTableName(); // Get Column Name // Adjust for Column reference table diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java b/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java index a06e9900b9..3503d4cbc8 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java @@ -173,15 +173,40 @@ public class PoExporter { } public void addTableReference(String columnName, String tableName, AttributesImpl atts) { - int id = po.get_Value(columnName) != null ? (Integer)po.get_Value(columnName) : -1; - addTableReference(columnName, tableName, id, atts); + if (tableName != null) { + MTable table = MTable.get(po.getCtx(), tableName, po.get_TrxName()); + if (table.isUUIDKeyTable()) { + String uuid = (String)po.get_Value(columnName); + addTableReferenceUUID(columnName, tableName, uuid, atts); + } else { + int id = po.get_Value(columnName) != null ? (Integer)po.get_Value(columnName) : -1; + addTableReference(columnName, tableName, id, atts); + } + } + } + + public void addTableReferenceMulti(String columnName, String tableName, AttributesImpl atts) { + if (tableName != null) { + String values = (String)po.get_Value(columnName); + addTableReferenceMulti(columnName, tableName, values, atts); + } } public void addTableReference(String columnName, String tableName, int id, AttributesImpl atts) { - String value = ReferenceUtils.getTableReference(tableName, id, atts); + String value = ReferenceUtils.getTableReference(tableName, id, atts, po.get_TrxName()); addString(columnName, value, atts); } + public void addTableReferenceUUID(String columnName, String tableName, String uuid, AttributesImpl atts) { + String value = ReferenceUtils.getTableReferenceUUID(tableName, uuid, atts); + addString(columnName, value, atts); + } + + public void addTableReferenceMulti(String columnName, String tableName, String values, AttributesImpl atts) { + String target_values = ReferenceUtils.getTableReferenceMulti(tableName, values, atts, po.get_TrxName()); + addString(columnName, target_values, atts); + } + public void export(List excludes) { export(excludes, false); } @@ -249,10 +274,10 @@ public class PoExporter { add(columnName, false, new AttributesImpl()); } else if (DisplayType.TableDir == displayType || DisplayType.ID == displayType) { String tableName = null; - if ("Record_ID".equalsIgnoreCase(columnName) && po.get_ColumnIndex("AD_Table_ID") >= 0) { - int AD_Table_ID = po.get_Value(po.get_ColumnIndex("AD_Table_ID")) != null - ? (Integer)po.get_Value(po.get_ColumnIndex("AD_Table_ID")) : 0; - tableName = MTable.getTableName(ctx.ctx, AD_Table_ID); + if (("Record_ID".equalsIgnoreCase(columnName) || "Record_UU".equalsIgnoreCase(columnName)) && po.get_ColumnIndex("AD_Table_ID") >= 0) { + int AD_Table_ID = po.get_ValueAsInt("AD_Table_ID"); + if (AD_Table_ID > 0) + tableName = MTable.get(ctx.ctx, AD_Table_ID, ctx.trx.getTrxName()).getTableName(); } else if (po.get_TableName().equals("AD_TreeNode") && columnName.equals("Parent_ID")) { int AD_Tree_ID = po.get_ValueAsInt("AD_Tree_ID"); MTree tree = new MTree(ctx.ctx, AD_Tree_ID, ctx.trx.getTrxName()); @@ -269,15 +294,20 @@ public class PoExporter { add(columnName, "", new AttributesImpl()); } else if (DisplayType.isLookup(displayType)) { String tableName = null; - if ("Record_ID".equalsIgnoreCase(columnName) && po.get_ColumnIndex("AD_Table_ID") >= 0) { - int AD_Table_ID = po.get_Value(po.get_ColumnIndex("AD_Table_ID")) != null - ? (Integer)po.get_Value(po.get_ColumnIndex("AD_Table_ID")) : 0; - tableName = MTable.getTableName(ctx.ctx, AD_Table_ID); + if (("Record_ID".equalsIgnoreCase(columnName) || "Record_UU".equalsIgnoreCase(columnName)) && po.get_ColumnIndex("AD_Table_ID") >= 0) { + int AD_Table_ID = po.get_ValueAsInt("AD_Table_ID"); + if (AD_Table_ID > 0) + tableName = MTable.get(ctx.ctx, AD_Table_ID, ctx.trx.getTrxName()).getTableName(); } else if (info.getColumnLookup(i) != null){ String lookupColumn = info.getColumnLookup(i).getColumnName(); tableName = lookupColumn.substring(0, lookupColumn.indexOf(".")); - } - addTableReference(columnName, tableName, new AttributesImpl()); + } + if ( info.getColumnDisplayType(i) == DisplayType.ChosenMultipleSelectionList + || DisplayType.isMultiID(info.getColumnDisplayType(i))) { + addTableReferenceMulti(columnName, tableName, new AttributesImpl()); + } else { + addTableReference(columnName, tableName, new AttributesImpl()); + } } else if (DisplayType.Account == displayType) { String tableName = "C_ValidCombination"; addTableReference(columnName, tableName, new AttributesImpl()); diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/PoFiller.java b/org.adempiere.pipo/src/org/adempiere/pipo2/PoFiller.java index 586727c82a..ed7829154d 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/PoFiller.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/PoFiller.java @@ -173,7 +173,7 @@ public class PoFiller{ * * @param qName */ - public int setTableReference(String qName) { + public Object setTableReference(String qName) { Element e = element.properties.get(qName); if (e == null) return 0; @@ -181,26 +181,35 @@ public class PoFiller{ String value = e.contents.toString(); String columnName = qName; if (value != null && value.trim().length() > 0) { - int id = ReferenceUtils.resolveReference(ctx.ctx, e, po.get_TrxName()); - if (columnName.equals("AD_Client_ID") && id > 0) { - if (id != Env.getAD_Client_ID(ctx.ctx)) { + MColumn col = MColumn.get(ctx.ctx, po.get_TableName(), columnName, po.get_TrxName()); + if (col == null) { + POInfo poInfo = POInfo.getPOInfo(ctx.ctx, po.get_Table_ID(), po.get_TrxName()); + col = new MColumn(ctx.ctx, poInfo.getAD_Column_ID(columnName), po.get_TrxName()); + if (col.get_ID() == 0) + return -1; + } + boolean isMulti = DisplayType.isMultiID(col.getAD_Reference_ID()); + Object id; + if (isMulti) + id = ReferenceUtils.resolveReferenceMulti(ctx.ctx, e, po.get_TrxName()); + else + id = ReferenceUtils.resolveReference(ctx.ctx, e, po.get_TrxName()); + if (columnName.equals("AD_Client_ID") && ((Number)id).intValue() > 0) { + if (((Number)id).intValue() != Env.getAD_Client_ID(ctx.ctx)) { return -1; } } if (po.get_ColumnIndex(columnName) >= 0) { - MColumn col = MColumn.get(ctx.ctx, po.get_TableName(), columnName, po.get_TrxName()); - if (col == null) { - POInfo poInfo = POInfo.getPOInfo(ctx.ctx, po.get_Table_ID(), po.get_TrxName()); - col = new MColumn(ctx.ctx, poInfo.getAD_Column_ID(columnName), po.get_TrxName()); - if (col.get_ID() == 0) - return -1; - } MTable foreignTable = null; - String refTableName = col.getReferenceTableName(); + String refTableName; + if (isMulti) + refTableName = col.getMultiReferenceTableName(); + else + refTableName = col.getReferenceTableName(); if (refTableName != null) { foreignTable = MTable.get(Env.getCtx(), refTableName, po.get_TrxName()); } else { - if ("Record_ID".equalsIgnoreCase(columnName)) { + if ("Record_ID".equalsIgnoreCase(columnName) || "Record_UU".equalsIgnoreCase(columnName)) { // special case - get the foreign table using AD_Table_ID int tableID = 0; try { @@ -220,31 +229,30 @@ public class PoFiller{ } } } - if (id > 0 && refTableName != null) { + if (id != null && refTableName != null) { if (foreignTable != null) { - /* Allow to read here from another tenant, cross tenant control is implemented later in a safe way */ - PO subPo = null; - try { - PO.setCrossTenantSafe(); - subPo = foreignTable.getPO(id, po.get_TrxName()); - } finally { - PO.clearCrossTenantSafe(); - } - if (subPo != null && subPo.getAD_Client_ID() != Env.getAD_Client_ID(ctx.ctx)) { - String accessLevel = foreignTable.getAccessLevel(); - if ((MTable.ACCESSLEVEL_All.equals(accessLevel) - || MTable.ACCESSLEVEL_SystemOnly.equals(accessLevel) - || MTable.ACCESSLEVEL_SystemPlusClient.equals(accessLevel)) && - subPo.getAD_Client_ID() != 0) + if (isMulti) { + for (String idstring : id.toString().split(",")) { + if (!isValidTenant(foreignTable, idstring, isMulti)) + return -1; + } + } else { + if (!isValidTenant(foreignTable, id, isMulti)) return -1; } } - if (po.get_ValueAsInt(columnName) != id) { - po.set_ValueNoCheck(columnName, id); - } + if (id instanceof String) { + if (!((String)id).equals(po.get_ValueAsString(columnName))) { + po.set_ValueNoCheck(columnName, id); + } + } else { + if (po.get_ValueAsInt(columnName) != ((Number)id).intValue()) { + po.set_ValueNoCheck(columnName, id); + } + } return id; - } else if (id == 0) { + } else if (id instanceof Number && ((Number)id).intValue() == 0) { if (refTableName != null && MTable.isZeroIDTable(refTableName)) { po.set_ValueNoCheck(columnName, id); return id; @@ -260,6 +268,38 @@ public class PoFiller{ } } + private boolean isValidTenant(MTable foreignTable, Object id, boolean isMulti) { + /* Allow to read here from another tenant, cross tenant control is implemented later in a safe way */ + PO subPo = null; + try { + PO.setCrossTenantSafe(); + if (id instanceof String) { + if (isMulti) { + subPo = foreignTable.getPO(Integer.valueOf(id.toString()), po.get_TrxName()); + } else { + subPo = foreignTable.getPOByUU((String)id, po.get_TrxName()); + } + } else { + if (((Number)id).intValue() == 0 && MTable.isZeroIDTable(foreignTable.getTableName())) + return true; + subPo = foreignTable.getPO(((Number)id).intValue(), po.get_TrxName()); + } + } finally { + PO.clearCrossTenantSafe(); + } + if (subPo != null && subPo.getAD_Client_ID() != Env.getAD_Client_ID(ctx.ctx)) { + String accessLevel = foreignTable.getAccessLevel(); + if ((MTable.ACCESSLEVEL_All.equals(accessLevel) + || MTable.ACCESSLEVEL_SystemOnly.equals(accessLevel) + || MTable.ACCESSLEVEL_SystemPlusClient.equals(accessLevel)) && + subPo.getAD_Client_ID() != 0) + return false; + } + if (subPo.is_new()) + return false; + return true; + } + /** * process all attributes * @param excludes list of attribute to exclude @@ -289,7 +329,7 @@ public class PoFiller{ } else if (sAD_Org_ID != null && sAD_Org_ID.equals("@AD_Org_ID@")) { po.setAD_Org_ID(Env.getAD_Org_ID(ctx.ctx)); } else { - if (setTableReference("AD_Client_ID") >= 0) + if (((Number)setTableReference("AD_Client_ID")).intValue() >= 0) setTableReference("AD_Org_ID"); } } @@ -310,8 +350,8 @@ public class PoFiller{ } Element e = element.properties.get(qName); if (ReferenceUtils.isLookup(e)) { - int id = setTableReference(qName); - if (id < 0) { + Object id = setTableReference(qName); + if (id == null || (id instanceof Number && ((Number)id).intValue() < 0)) { notFounds.add(qName); } } else { diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/ReferenceUtils.java b/org.adempiere.pipo/src/org/adempiere/pipo2/ReferenceUtils.java index c1a28493f8..ebf5126b46 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/ReferenceUtils.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/ReferenceUtils.java @@ -7,6 +7,7 @@ import org.compiere.model.PO; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; +import org.compiere.util.Util; import org.xml.sax.helpers.AttributesImpl; public class ReferenceUtils { @@ -21,7 +22,22 @@ public class ReferenceUtils { * @param trxName * @return positive id if found */ - public static int resolveReference(Properties ctx, Element e, String trxName) + public static int resolveReferenceAsInt(Properties ctx, Element e, String trxName) + { + Object id = resolveReference(ctx, e, trxName); + if (id instanceof Number) + return ((Number)id).intValue(); + return -1; + } + + /** + * + * @param ctx + * @param e + * @param trxName + * @return positive id if found + */ + public static Object resolveReference(Properties ctx, Element e, String trxName) { String value = e.contents.toString(); String referenceKey = e.attributes.getValue("reference-key"); @@ -36,7 +52,7 @@ public class ReferenceUtils { { String uuid = value.trim(); String target = Env.getAD_Client_ID(ctx) > 0 ? POFinder.getTargetUUID(ctx, referenceKey, uuid, trxName) : uuid; - int id = IDFinder.findIdByColumn(referenceKey, PO.getUUIDColumnName(referenceKey), target, Env.getAD_Client_ID(ctx), trxName); + Object id = IDFinder.findIdByColumn(referenceKey, PO.getUUIDColumnName(referenceKey), target, Env.getAD_Client_ID(ctx), trxName); return id; } else @@ -50,6 +66,36 @@ public class ReferenceUtils { } } + /** + * + * @param ctx + * @param e + * @param trxName + * @return list of IDs or UUIDs if found + */ + public static Object resolveReferenceMulti(Properties ctx, Element e, String trxName) + { + String values = e.contents.toString(); + String referenceKey = e.attributes.getValue("reference-key"); + if (values != null && values.trim().length() > 0) { + String target_values = null; + for (String uuid : values.split(",")) { + // multi is always UUID, even for official IDs + String target = Env.getAD_Client_ID(ctx) > 0 ? POFinder.getTargetUUID(ctx, referenceKey, uuid, trxName) : uuid; + Object id = IDFinder.findIdByColumn(referenceKey, PO.getUUIDColumnName(referenceKey), target, Env.getAD_Client_ID(ctx), trxName); + if (id == null) // one of the multi UUID was not found, invalidate the complete string + return -1; + if (target_values == null) + target_values = id.toString(); + else + target_values += "," + id.toString(); + } + return target_values; + } else { + return 0; + } + } + public static boolean isLookup(Element element) { if (isIDLookup(element) || isUUIDLookup(element)) @@ -68,7 +114,7 @@ public class ReferenceUtils { return "uuid".equals(element.attributes.getValue("reference")); } - public static String getTableReference(String tableName, int id, AttributesImpl atts) + public static String getTableReference(String tableName, int id, AttributesImpl atts, String trxName) { String keyColumn = tableName + "_ID"; if ( (id > 0 && id <= PackOut.MAX_OFFICIAL_ID) @@ -87,7 +133,7 @@ public class ReferenceUtils { } else { - MTable table = MTable.get(Env.getCtx(), tableName); + MTable table = MTable.get(Env.getCtx(), tableName, trxName); if (table == null) throw new RuntimeException("Table Not Found. TableName="+tableName); String uuidColumnName = PO.getUUIDColumnName(tableName); @@ -110,6 +156,62 @@ public class ReferenceUtils { atts.addAttribute("", "", "reference", "CDATA", "id"); return ""; } -} + public static String getTableReferenceUUID(String tableName, String uuid, AttributesImpl atts) + { + if (Util.isEmpty(uuid)) + { + //no uuid + atts.addAttribute("", "", "reference", "CDATA", "uuid"); + return ""; + } + else + { + //uuid + atts.addAttribute("", "", "reference", "CDATA", "uuid"); + atts.addAttribute("", "", "reference-key", "CDATA", tableName); + return uuid.trim(); + } + } + public static String getTableReferenceMulti(String tableName, String values, AttributesImpl atts, String trxName) + { + atts.addAttribute("", "", "reference", "CDATA", "uuid"); + if (Util.isEmpty(values)) { + return ""; + } + MTable table = MTable.get(Env.getCtx(), tableName, trxName); + if (table == null) + throw new RuntimeException("Table Not Found. TableName="+tableName); + if (table.isUUIDKeyTable()) { + //uuid + atts.addAttribute("", "", "reference-key", "CDATA", tableName); + return values.trim(); + } + + // convert multi-IDs to multi-UUIDs + String target_values = ""; + String keyColumn = tableName + "_ID"; + String uuidColumnName = PO.getUUIDColumnName(tableName); + for (String value : values.split(",")) { + int id = Integer.valueOf(value); + // Translate always IDs to UUIDs, even for official IDs, + // because it would be more complex to manage a combination of official IDs and UUIDs + if (table.getColumn(uuidColumnName) != null) { + //uuid + String sql = "SELECT " + uuidColumnName + " FROM " + + tableName + " WHERE " + keyColumn + " = ?"; + String valuePartial = DB.getSQLValueString(null, sql, id); + if (!Util.isEmpty(valuePartial, true)) { + if (target_values.length() == 0) + target_values = valuePartial; + else + target_values += "," + valuePartial; + } + } + } + atts.addAttribute("", "", "reference-key", "CDATA", tableName); + return target_values; + } + +} \ No newline at end of file