IDEMPIERE-4653 Improve timeout handling of window tab (#539)
* IDEMPIERE-4653 Improve timeout handling of window tab * Fixed a problem with IDEMPIERE-4130 that was not using role max query records * GridTable was throwing NPEs because the arrays were disposed before closing * Lowered log level on MRole to avoid clogging the console (I was testing with INFO level) * Added more points of control for the timeout exception to give meaningful errors to the user and allow refining the query without closing the Find dialog * Implemented a control to avoid repeating a slow initial query every time the dialog is open * Added dialog when the find criteria doesn't return rows and allows the user to refine the query * When the initial number of records is unknown, show a question mark instead of the count * * Fix wrong role level pushed in first commit
This commit is contained in:
parent
e1ba21360f
commit
24ccb86f16
|
@ -3437,7 +3437,7 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
|
|||
// minimum between AD_Tab.MaxQueryRecords and AD_Role.MaxQueryRecords
|
||||
int roleMaxQueryRecords = MRole.getDefault().getMaxQueryRecords();
|
||||
int tabMaxQueryRecords = m_vo.MaxQueryRecords;
|
||||
if (roleMaxQueryRecords > 0 && roleMaxQueryRecords < tabMaxQueryRecords)
|
||||
if (roleMaxQueryRecords > 0 && (roleMaxQueryRecords < tabMaxQueryRecords || tabMaxQueryRecords == 0))
|
||||
tabMaxQueryRecords = roleMaxQueryRecords;
|
||||
return tabMaxQueryRecords;
|
||||
}
|
||||
|
|
|
@ -785,21 +785,22 @@ public class GridTable extends AbstractTableModel
|
|||
if (m_buffer != null)
|
||||
{
|
||||
m_buffer.clear();
|
||||
m_buffer = null;
|
||||
}
|
||||
if (m_sort != null)
|
||||
{
|
||||
m_sort.clear();
|
||||
m_sort = null;
|
||||
}
|
||||
if (m_virtualBuffer != null)
|
||||
{
|
||||
m_virtualBuffer.clear();
|
||||
m_virtualBuffer = null;
|
||||
}
|
||||
|
||||
if (finalCall)
|
||||
if (finalCall) {
|
||||
dispose();
|
||||
m_buffer = null;
|
||||
m_sort = null;
|
||||
m_virtualBuffer = null;
|
||||
}
|
||||
|
||||
// Fields are disposed from MTab
|
||||
log.fine("");
|
||||
|
@ -3698,7 +3699,7 @@ public class GridTable extends AbstractTableModel
|
|||
}
|
||||
} // while(rs.next())
|
||||
}
|
||||
catch (SQLException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE, "run", e);
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ public final class MRole extends X_AD_Role implements ImmutablePOSupport
|
|||
*/
|
||||
public synchronized static MRole get (Properties ctx, int AD_Role_ID, int AD_User_ID, boolean reload)
|
||||
{
|
||||
if (s_log.isLoggable(Level.INFO)) s_log.info("AD_Role_ID=" + AD_Role_ID + ", AD_User_ID=" + AD_User_ID + ", reload=" + reload);
|
||||
if (s_log.isLoggable(Level.CONFIG)) s_log.config("AD_Role_ID=" + AD_Role_ID + ", AD_User_ID=" + AD_User_ID + ", reload=" + reload);
|
||||
String key = AD_Role_ID + "_" + AD_User_ID;
|
||||
MRole role = (MRole)s_roles.get (key, e -> new MRole(ctx, e));
|
||||
if (role == null || reload)
|
||||
|
|
|
@ -1172,7 +1172,7 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
|||
{
|
||||
if (DBException.isTimeout(e))
|
||||
{
|
||||
FDialog.error(windowNo, GridTable.LOAD_TIMEOUT_ERROR_MESSAGE);
|
||||
throw e;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ import static org.compiere.model.MSysConfig.ZK_GRID_AFTER_FIND;
|
|||
import static org.compiere.model.SystemIDs.PROCESS_AD_CHANGELOG_REDO;
|
||||
import static org.compiere.model.SystemIDs.PROCESS_AD_CHANGELOG_UNDO;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -660,7 +661,13 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
|||
fTabPanel.createUI();
|
||||
if (!m_queryInitiating)
|
||||
{
|
||||
initFirstTabpanel();
|
||||
try {
|
||||
initFirstTabpanel();
|
||||
} catch (Exception e) {
|
||||
if (DBException.isTimeout(e)) {
|
||||
FDialog.error(curWindowNo, GridTable.LOAD_TIMEOUT_ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2994,7 +3001,18 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
|||
if (query != null) {
|
||||
m_onlyCurrentRows = false;
|
||||
adTabbox.getSelectedGridTab().setQuery(query);
|
||||
adTabbox.getSelectedTabpanel().query(m_onlyCurrentRows, m_onlyCurrentDays, MRole.getDefault().getMaxQueryRecords()); // autoSize
|
||||
try {
|
||||
adTabbox.getSelectedTabpanel().query(m_onlyCurrentRows, m_onlyCurrentDays, MRole.getDefault().getMaxQueryRecords()); // autoSize
|
||||
} catch (Exception e) {
|
||||
if ( e.getCause() != null
|
||||
&& e.getCause() instanceof SQLException
|
||||
&& DB.getDatabase().isQueryTimeout((SQLException)e.getCause())) {
|
||||
// ignore, is captured somewhere else
|
||||
return;
|
||||
} else {
|
||||
throw new DBException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adTabbox.getSelectedGridTab().dataRefresh(false);
|
||||
|
|
|
@ -135,7 +135,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3968142284124286827L;
|
||||
private static final long serialVersionUID = -5087378621976257241L;
|
||||
|
||||
private static final String FIND_ROW_EDITOR = "find.row.editor";
|
||||
|
||||
|
@ -190,6 +190,8 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
private static final CLogger log = CLogger.getCLogger(FindWindow.class);
|
||||
/** Number of records */
|
||||
private int m_total;
|
||||
/** Initial slow query */
|
||||
private boolean initialSlowQuery = false;
|
||||
private PreparedStatement m_pstmt;
|
||||
//
|
||||
/** List of WEditors */
|
||||
|
@ -247,6 +249,8 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
|
||||
private static final String ON_POST_VISIBLE_ATTR = "onPostVisible.Event.Posted";
|
||||
|
||||
private static final int COUNTING_RECORDS_TIMED_OUT = -255;
|
||||
|
||||
/** START DEVCOFFEE **/
|
||||
private StatusBarPanel statusBar = new StatusBarPanel();
|
||||
/** END DEVCOFFEE **/
|
||||
|
@ -315,7 +319,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
initFind();
|
||||
initFindAdvanced();
|
||||
|
||||
if (m_total < m_minRecords)
|
||||
if (m_total != COUNTING_RECORDS_TIMED_OUT && m_total < m_minRecords)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -350,7 +354,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
|
||||
m_minRecords = minRecords;
|
||||
m_total = getNoOfRecords(null, false);
|
||||
if (m_total < m_minRecords)
|
||||
if (m_total != COUNTING_RECORDS_TIMED_OUT && m_total < m_minRecords)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1479,15 +1483,10 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
{
|
||||
fQueryName.setSelectedIndex(0);
|
||||
cmd_ok_Simple();
|
||||
if (advancedPanel != null) {
|
||||
advancedPanel.getItems().clear();
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
else if ("btnOkAdv".equals(btn.getName()))
|
||||
{
|
||||
cmd_ok_Advanced();
|
||||
dispose();
|
||||
}
|
||||
else if("btnCancel".equals(btn.getName()))
|
||||
{
|
||||
|
@ -1524,12 +1523,10 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
if (winLookupRecord.equals(event.getTarget()))
|
||||
{
|
||||
cmd_ok_Simple();
|
||||
dispose();
|
||||
}
|
||||
else if (winAdvanced.equals(event.getTarget()))
|
||||
{
|
||||
cmd_ok_Advanced();
|
||||
dispose();
|
||||
}
|
||||
// Check simple panel fields
|
||||
for (int i = 0; i < m_sEditors.size(); i++)
|
||||
|
@ -1538,13 +1535,11 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
if (editor.getComponent() == event.getTarget())
|
||||
{
|
||||
cmd_ok_Simple();
|
||||
dispose();
|
||||
}
|
||||
WEditor editorTo = (WEditor)m_sEditorsTo.get(i);
|
||||
if (editorTo != null && editor.getComponent() == event.getTarget())
|
||||
{
|
||||
cmd_ok_Simple();
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2354,8 +2349,16 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
cmd_saveSimple(false, false);
|
||||
|
||||
// Test for no records
|
||||
if (getNoOfRecords(m_query, true) != 0)
|
||||
dispose();
|
||||
if (getNoOfRecords(m_query, true) != 0) {
|
||||
if (m_total == COUNTING_RECORDS_TIMED_OUT) {
|
||||
FDialog.error(m_targetWindowNo, "InfoQueryTimeOutError");
|
||||
} else {
|
||||
if (advancedPanel != null) {
|
||||
advancedPanel.getItems().clear();
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
} // cmd_ok_Simple
|
||||
|
||||
|
@ -2428,8 +2431,13 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
addHistoryRestriction(historyCombo.getSelectedItem());
|
||||
}
|
||||
|
||||
if (getNoOfRecords(m_query, true) != 0)
|
||||
dispose();
|
||||
if (getNoOfRecords(m_query, true) != 0) {
|
||||
if (m_total == COUNTING_RECORDS_TIMED_OUT) {
|
||||
FDialog.error(m_targetWindowNo, "InfoQueryTimeOutError");
|
||||
} else {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
} // cmd_ok_Advanced
|
||||
|
||||
/**
|
||||
|
@ -2443,13 +2451,15 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
/**
|
||||
* Get the number of records of target tab
|
||||
* @param query where clause for target tab
|
||||
* @param alertZeroRecords show dialog if there are no records
|
||||
* @param alertRecords show dialog if there are no records or there are more records than allowed for role/tab
|
||||
* @return number of selected records;
|
||||
* if the results are more then allowed this method will return 0
|
||||
**/
|
||||
private int getNoOfRecords (MQuery query, boolean alertZeroRecords)
|
||||
private int getNoOfRecords (MQuery query, boolean alertRecords)
|
||||
{
|
||||
if (log.isLoggable(Level.CONFIG)) log.config("" + query);
|
||||
if (initialSlowQuery && (query == null || query.getRestrictionCount() == 0))
|
||||
return COUNTING_RECORDS_TIMED_OUT;
|
||||
StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM ");
|
||||
sql.append(m_tableName);
|
||||
boolean hasWhere = false;
|
||||
|
@ -2492,7 +2502,10 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
{
|
||||
if (DB.getDatabase().isQueryTimeout(e))
|
||||
{
|
||||
throw new DBException(Msg.getMsg(Env.getCtx(), GridTable.LOAD_TIMEOUT_ERROR_MESSAGE));
|
||||
m_total = COUNTING_RECORDS_TIMED_OUT; // unknown
|
||||
if (query == null) {
|
||||
initialSlowQuery = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2506,10 +2519,10 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
stmt = null;
|
||||
}
|
||||
// No Records
|
||||
/* if (m_total == 0 && alertZeroRecords)
|
||||
FDialog.warn(m_targetWindowNo, this, "FindZeroRecords");*/
|
||||
if (m_total == 0 && alertRecords)
|
||||
FDialog.warn(m_targetWindowNo, this, "FindZeroRecords", null);
|
||||
// More then allowed
|
||||
if (m_gridTab != null && query != null && m_gridTab.isQueryMax(m_total))
|
||||
if (m_gridTab != null && alertRecords && m_total != COUNTING_RECORDS_TIMED_OUT && m_gridTab.isQueryMax(m_total))
|
||||
{
|
||||
FDialog.error(m_targetWindowNo, this, "FindOverMax",
|
||||
m_total + " > " + m_gridTab.getMaxQueryRecords());
|
||||
|
@ -2700,7 +2713,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
*/
|
||||
public MQuery getQuery()
|
||||
{
|
||||
if (m_gridTab != null && m_gridTab.isQueryMax(getTotalRecords()) && !m_isCancel)
|
||||
if (m_gridTab != null && m_total != COUNTING_RECORDS_TIMED_OUT && m_gridTab.isQueryMax(m_total) && !m_isCancel)
|
||||
{
|
||||
m_query = MQuery.getNoRecordQuery (m_tableName, false);
|
||||
m_total = 0;
|
||||
|
@ -2867,7 +2880,7 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
|||
*/
|
||||
private void setStatusDB (int currentCount)
|
||||
{
|
||||
StringBuilder text = new StringBuilder(" ").append(Msg.getMsg(Env.getCtx(), "Records")).append(" = ").append(m_total).append(" ");
|
||||
StringBuilder text = new StringBuilder(" ").append(Msg.getMsg(Env.getCtx(), "Records")).append(" = ").append(m_total == COUNTING_RECORDS_TIMED_OUT ? "?" : m_total).append(" ");
|
||||
statusBar.setStatusDB(text.toString());
|
||||
} // setDtatusDB
|
||||
/** END DEVCOFFEE **/
|
||||
|
|
Loading…
Reference in New Issue