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
This commit is contained in:
Carlos Ruiz 2023-08-26 03:49:39 +02:00 committed by GitHub
parent c1d8a50b12
commit 954b3b2fec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 391 additions and 140 deletions

View File

@ -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);

View File

@ -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());

View File

@ -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);
}
/**************************************************************************

View File

@ -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)

View File

@ -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,12 +220,21 @@ 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);
if (table.isUUIDKeyTable())
pstmt.setString(1, parent.get_UUID());
else
pstmt.setInt(1, parent.get_ID());
rs = pstmt.executeQuery();
while (rs.next()) {

View File

@ -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);

View File

@ -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");

View File

@ -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()) {

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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 Map<String, Integer>idCache = new ConcurrentHashMap<String, Integer>();
private static Map<String, Object>idCache = new ConcurrentHashMap<String, Object>();
/**
* 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,9 +165,13 @@ public class IDFinder {
}
rs = pstmt.executeQuery();
if (rs.next())
if (rs.next()) {
if (table.isUUIDKeyTable())
id = rs.getString(1);
else
id = rs.getInt(1);
}
}
catch (Exception e) {
throw new DatabaseAccessException(e);
} finally {
@ -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,12 +465,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 sql = new StringBuilder("SELECT ")
.append(tableName)
.append("_ID ")
.append(keycol)
.append(" FROM ")
.append(tableName)
.append(" ")
.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;

View File

@ -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);

View File

@ -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

View File

@ -173,15 +173,40 @@ public class PoExporter {
}
public void addTableReference(String columnName, String tableName, AttributesImpl 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<String> 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("."));
}
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());

View File

@ -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,13 +181,6 @@ 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)) {
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());
@ -195,12 +188,28 @@ public class PoFiller{
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) {
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 (isMulti) {
for (String idstring : id.toString().split(",")) {
if (!isValidTenant(foreignTable, idstring, isMulti))
return -1;
}
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)
} else {
if (!isValidTenant(foreignTable, id, isMulti))
return -1;
}
}
if (po.get_ValueAsInt(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 {

View File

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