Advertisement
tko_pb

auditTrailPopUp.java

Nov 28th, 2018
458
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 66.58 KB | None | 0 0
  1. /*
  2.  *************************************************************************
  3.  * The contents of this file are subject to the Openbravo  Public  License
  4.  * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
  5.  * Version 1.1  with a permitted attribution clause; you may not  use this
  6.  * file except in compliance with the License. You  may  obtain  a copy of
  7.  * the License at http://www.openbravo.com/legal/license.html
  8.  * Software distributed under the License  is  distributed  on  an "AS IS"
  9.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  10.  * License for the specific  language  governing  rights  and  limitations
  11.  * under the License.
  12.  * The Original Code is Openbravo ERP.
  13.  * The Initial Developer of the Original Code is Openbravo SLU
  14.  * All portions are Copyright (C) 2009-2016 Openbravo SLU
  15.  * All Rights Reserved.
  16.  * Contributor(s):  ______________________________________.
  17.  ************************************************************************
  18.  */
  19. package org.openbravo.erpCommon.businessUtility;
  20.  
  21. import java.io.IOException;
  22. import java.io.PrintWriter;
  23. import java.text.ParseException;
  24. import java.text.SimpleDateFormat;
  25. import java.util.ArrayList;
  26. import java.util.Collection;
  27. import java.util.Date;
  28. import java.util.HashMap;
  29. import java.util.List;
  30. import java.util.Map;
  31.  
  32. import javax.servlet.ServletConfig;
  33. import javax.servlet.ServletException;
  34. import javax.servlet.http.HttpServletRequest;
  35. import javax.servlet.http.HttpServletResponse;
  36.  
  37. import org.apache.commons.lang.StringEscapeUtils;
  38. import org.hibernate.FetchMode;
  39. import org.hibernate.criterion.Order;
  40. import org.hibernate.criterion.Restrictions;
  41. import org.openbravo.base.filter.IsIDFilter;
  42. import org.openbravo.base.filter.IsPositiveIntFilter;
  43. import org.openbravo.base.filter.RequestFilter;
  44. import org.openbravo.base.filter.ValueListFilter;
  45. import org.openbravo.base.model.Entity;
  46. import org.openbravo.base.model.ModelProvider;
  47. import org.openbravo.base.model.Property;
  48. import org.openbravo.base.secureApp.HttpSecureAppServlet;
  49. import org.openbravo.base.secureApp.VariablesSecureApp;
  50. import org.openbravo.base.structure.BaseOBObject;
  51. import org.openbravo.client.application.Process;
  52. import org.openbravo.dal.core.OBContext;
  53. import org.openbravo.dal.service.OBCriteria;
  54. import org.openbravo.dal.service.OBDal;
  55. import org.openbravo.dal.service.OBQuery;
  56. import org.openbravo.data.FieldProvider;
  57. import org.openbravo.erpCommon.obps.ActivationKey;
  58. import org.openbravo.erpCommon.obps.ActivationKey.FeatureRestriction;
  59. import org.openbravo.erpCommon.utility.ComboTableData;
  60. import org.openbravo.erpCommon.utility.OBError;
  61. import org.openbravo.erpCommon.utility.SQLReturnObject;
  62. import org.openbravo.erpCommon.utility.Utility;
  63. import org.openbravo.erpCommon.utility.UtilityData;
  64. import org.openbravo.model.ad.access.AuditTrailRaw;
  65. import org.openbravo.model.ad.access.User;
  66. import org.openbravo.model.ad.datamodel.Column;
  67. import org.openbravo.model.ad.datamodel.Table;
  68. import org.openbravo.model.ad.domain.Callout;
  69. import org.openbravo.model.ad.domain.ListTrl;
  70. import org.openbravo.model.ad.domain.Reference;
  71. import org.openbravo.model.ad.system.Language;
  72. import org.openbravo.model.ad.ui.Element;
  73. import org.openbravo.model.ad.ui.ElementTrl;
  74. import org.openbravo.model.ad.ui.Field;
  75. import org.openbravo.model.ad.ui.FieldTrl;
  76. import org.openbravo.model.ad.ui.Form;
  77. import org.openbravo.model.ad.ui.FormTrl;
  78. import org.openbravo.model.ad.ui.Message;
  79. import org.openbravo.model.ad.ui.MessageTrl;
  80. import org.openbravo.model.ad.ui.ProcessTrl;
  81. import org.openbravo.model.ad.ui.Tab;
  82. import org.openbravo.model.ad.ui.TabTrl;
  83. import org.openbravo.model.ad.ui.Window;
  84. import org.openbravo.model.ad.ui.WindowTrl;
  85. import org.openbravo.reference.ui.UIReference;
  86. import org.openbravo.xmlEngine.XmlDocument;
  87.  
  88. public class AuditTrailPopup extends HttpSecureAppServlet {
  89.   private static final long serialVersionUID = 1L;
  90.  
  91.   private static final String auditActionsReferenceId = "4C36DC179A5F40DC80B3F3798E121152";
  92.   private static final String adMessageIdForProcess = "437";
  93.   private static final String adMessageIdForWindow = "614";
  94.   private static final String adMessageIdForCF = "32171A3EEE4847FABB69259868A34ED5";
  95.   private static final String adMessageIdForForm = "D9912E810888475ABB8DFF416196FB5E";
  96.   private static final String adMessageIdForCallout = "13F1AE1374AD4054BE7FD3743B56F266";
  97.   private static final String adValRuleIdForFields = "9C6989B15CEA4987A502C0F5FF02B171";
  98.  
  99.   private static final String[] colNamesHistory = { "time", "action", "user", "process", "field",
  100.       "old_value", "new_value", "rowkey" };
  101.   private static final RequestFilter columnFilterHistory = new ValueListFilter(colNamesHistory);
  102.   private static final RequestFilter directionFilter = new ValueListFilter("asc", "desc");
  103.  
  104.   public void init(ServletConfig config) {
  105.     super.init(config);
  106.     boolHist = false;
  107.   }
  108.  
  109.   public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException,
  110.       ServletException {
  111.     VariablesSecureApp vars = new VariablesSecureApp(request);
  112.  
  113.     // Prevent execution in Community instances
  114.     if (!ActivationKey.getInstance().isActive()) {
  115.       licenseError(classInfo.type, classInfo.id, FeatureRestriction.TIER1_RESTRICTION, response,
  116.           request, vars, true);
  117.     }
  118.  
  119.     String accesTabId = vars.getGlobalVariable("inpTabId", "AuditTrail.tabId", IsIDFilter.instance);
  120.     if (!hasGeneralAccess(vars, "W", accesTabId)) {
  121.       // do security check based on tabId passed in
  122.       bdErrorGeneralPopUp(request, response, Utility.messageBD(this, "Error", vars.getLanguage()),
  123.           Utility.messageBD(this, "AccessTableNoView", vars.getLanguage()));
  124.     }
  125.  
  126.     // all code runs in adminMode to get read access to i.e. Tab,TabTrl,AD_Audit_Trail entities
  127.     OBContext.setAdminMode();
  128.     try {
  129.  
  130.       if (vars.commandIn("POPUP_HISTORY")) {
  131.         // popup showing the history of a single record
  132.  
  133.         removePageSessionVariables(vars);
  134.         vars.removeSessionValue("AuditTrail.tabId");
  135.         vars.removeSessionValue("AuditTrail.tableId");
  136.         vars.removeSessionValue("AuditTrail.recordId");
  137.  
  138.         // read request params, and save in session
  139.         String tabId = vars.getGlobalVariable("inpTabId", "AuditTrail.tabId", IsIDFilter.instance);
  140.         String tableId = vars.getGlobalVariable("inpTableId", "AuditTrail.tableId",
  141.             IsIDFilter.instance);
  142.         // recordId is optional as popup can be called from empty grid
  143.         String recordId = vars.getGlobalVariable("inpRecordId", "AuditTrail.recordId", false,
  144.             false, false, "", IsIDFilter.instance);
  145.         printPagePopupHistory(response, vars, tabId, tableId, recordId);
  146.  
  147.       } else if (vars.commandIn("STRUCTURE_HISTORY")) {
  148.         // called from the DataGrid.js STRUCTURE request
  149.         printGridStructureHistory(response, vars);
  150.  
  151.       } else if (vars.commandIn("DATA_HISTORY")) {
  152.         // called from the DataGrid.js DATA request
  153.         if (vars.getStringParameter("newFilter").equals("1")) {
  154.           removePageSessionVariables(vars);
  155.         }
  156.         String tableId = vars.getGlobalVariable("inpTableId", "AuditTrail.tableId",
  157.             IsIDFilter.instance);
  158.         String tabId = vars.getGlobalVariable("inpTabId", "AuditTrail.tabId", IsIDFilter.instance);
  159.         // recordId is optional as popup can be called from empty grid
  160.         String recordId = vars.getGlobalVariable("inpRecordId", "AuditTrail.recordId", false,
  161.             false, false, "", IsIDFilter.instance);
  162.  
  163.         // filter fields
  164.         String userId = vars.getGlobalVariable("inpUser", "AuditTrail.userId", "",
  165.             IsIDFilter.instance);
  166.         String fieldId = vars.getGlobalVariable("inpField", "AuditTrail.fieldId", "",
  167.             IsIDFilter.instance);
  168.         String dateFrom = vars.getGlobalVariable("inpDateFrom", "AuditTrail.dateFrom", "");
  169.         String dateTo = vars.getGlobalVariable("inpDateTo", "AuditTrail.dateTo", "");
  170.  
  171.         String strNewFilter = vars.getStringParameter("newFilter");
  172.         String strOffset = vars.getStringParameter("offset", IsPositiveIntFilter.instance);
  173.         String strPageSize = vars.getStringParameter("page_size", IsPositiveIntFilter.instance);
  174.         // not used right now, as grid is defined as non-sortable
  175.         String strSortCols = vars.getInStringParameter("sort_cols", columnFilterHistory);
  176.         String strSortDirs = vars.getInStringParameter("sort_dirs", directionFilter);
  177.         printGridDataHistory(response, vars, tableId, tabId, recordId, userId, fieldId, dateFrom,
  178.             dateTo, strSortCols, strSortDirs, strOffset, strPageSize, strNewFilter);
  179.  
  180.       } else if (vars.commandIn("POPUP_DELETED")) {
  181.         // popup showing all deleted records of a single tab
  182.  
  183.         removePageSessionVariables(vars);
  184.         vars.removeSessionValue("AuditTrail.recordId");
  185.         vars.removeSessionValue("AuditTrail.tabId");
  186.         vars.removeSessionValue("AuditTrail.tableId");
  187.  
  188.         // read request params, and save in session
  189.         String tabId = vars.getGlobalVariable("inpTabId", "AuditTrail.tabId", IsIDFilter.instance);
  190.         String tableId = vars.getGlobalVariable("inpTableId", "AuditTrail.tableId",
  191.             IsIDFilter.instance);
  192.  
  193.         // recordId is optional as popup can be called from empty grid
  194.         String recordId = vars.getGlobalVariable("inpRecordId", "AuditTrail.recordId", false,
  195.             false, false, "", IsIDFilter.instance);
  196.         printPagePopupDeleted(response, vars, recordId, tabId, tableId);
  197.  
  198.       } else if (vars.commandIn("STRUCTURE_DELETED")) {
  199.         // called from the DataGrid.js STRUCTURE request
  200.         String tabId = vars.getGlobalVariable("inpTabId", "AuditTrail.tabId", IsIDFilter.instance);
  201.         String tableId = vars.getGlobalVariable("inpTableId", "AuditTrail.tableId",
  202.             IsIDFilter.instance);
  203.         printGridStructureDeleted(response, vars, tabId, tableId);
  204.  
  205.       } else if (vars.commandIn("DATA_DELETED")) {
  206.         // called from the DataGrid.js DATA request
  207.         if (vars.getStringParameter("newFilter").equals("1")) {
  208.           removePageSessionVariables(vars);
  209.         }
  210.         String tabId = vars.getGlobalVariable("inpTabId", "AuditTrail.tabId", IsIDFilter.instance);
  211.         String tableId = vars.getGlobalVariable("inpTableId", "AuditTrail.tableId",
  212.             IsIDFilter.instance);
  213.  
  214.         // filter fields
  215.         String dateFrom = vars.getGlobalVariable("inpDateFrom", "AuditTrail.dateFrom", "");
  216.         String dateTo = vars.getGlobalVariable("inpDateTo", "AuditTrail.dateTo", "");
  217.         String userId = vars.getGlobalVariable("inpUser", "AuditTrail.userId", "",
  218.             IsIDFilter.instance);
  219.  
  220.         String strNewFilter = vars.getStringParameter("newFilter");
  221.         String strOffset = vars.getStringParameter("offset", IsPositiveIntFilter.instance);
  222.         String strPageSize = vars.getStringParameter("page_size", IsPositiveIntFilter.instance);
  223.         // not used right now, as grid is defined as non-sortable
  224.         String strSortCols = vars.getInStringParameter("sort_cols", columnFilterHistory);
  225.         String strSortDirs = vars.getInStringParameter("sort_dirs", directionFilter);
  226.         printGridDataDeleted(response, vars, tabId, tableId, dateFrom, dateTo, userId, strSortCols,
  227.             strSortDirs, strOffset, strPageSize, strNewFilter);
  228.       } else {
  229.         pageError(response);
  230.       }
  231.     } finally {
  232.       OBContext.restorePreviousMode();
  233.     }
  234.   }
  235.  
  236.   private void removePageSessionVariables(VariablesSecureApp vars) {
  237.     vars.removeSessionValue("AuditTrail.userId");
  238.     vars.removeSessionValue("AuditTrail.fieldId");
  239.     vars.removeSessionValue("AuditTrail.dateFrom");
  240.     vars.removeSessionValue("AuditTrail.dateTo");
  241.     // only remove the following values on initial open of the popup, not on a filter change
  242.     if (vars.getStringParameter("newFilter").equals("1")) {
  243.       return;
  244.     }
  245.     vars.removeSessionValue("AuditTrail.fkColumnName");
  246.     vars.removeSessionValue("AuditTrail.fkId");
  247.   }
  248.  
  249.   private void printPagePopupHistory(HttpServletResponse response, VariablesSecureApp vars,
  250.       String tabId, String tableId, String recordId) throws IOException {
  251.     log4j.debug("POPUP-HISTORY - tabId: " + tabId + ", tableId: " + tableId + ", inpRecordId: "
  252.         + recordId);
  253.  
  254.     XmlDocument xmlDocument = xmlEngine.readXmlTemplate(
  255.         "org/openbravo/erpCommon/businessUtility/AuditTrailPopupHistory").createXmlDocument();
  256.  
  257.     xmlDocument.setParameter("directory", "var baseDirectory = \"" + strReplaceWith + "/\";\n");
  258.     xmlDocument.setParameter("language", "defaultLang=\"" + vars.getLanguage() + "\";");
  259.     // calendar language has extra parameter
  260.     xmlDocument.setParameter("calendar", vars.getLanguage().substring(0, 2));
  261.     xmlDocument.setParameter("theme", vars.getTheme());
  262.  
  263.     xmlDocument.setParameter("jsFocusOnField", Utility.focusFieldJS("paramDateFrom"));
  264.  
  265.     xmlDocument.setParameter("grid", "20");
  266.     xmlDocument.setParameter("grid_Offset", "");
  267.     xmlDocument.setParameter("grid_SortCols", "1");
  268.     xmlDocument.setParameter("grid_SortDirs", "DESC");
  269.     xmlDocument.setParameter("grid_Default", "0");
  270.  
  271.     // display/save-formats for the datetime fields
  272.     xmlDocument
  273.         .setParameter("dateFromdisplayFormat", vars.getSessionValue("#AD_SqlDateTimeFormat"));
  274.     xmlDocument.setParameter("dateFromsaveFormat", vars.getJavaDataTimeFormat());
  275.     xmlDocument.setParameter("dateTodisplayFormat", vars.getSessionValue("#AD_SqlDateTimeFormat"));
  276.     xmlDocument.setParameter("dateTosaveFormat", vars.getJavaDataTimeFormat());
  277.  
  278.     // user combobox (restricted to login users only)
  279.     try {
  280.       ComboTableData cmd = new ComboTableData(vars, this, "19", "AD_User_ID", "",
  281.           "C48E4CAE3C2A4C5DBC2E011D8AD2C428", Utility.getContext(this, vars, "#AccessibleOrgTree",
  282.               "AuditTrailPopup"),
  283.           Utility.getContext(this, vars, "#User_Client", "AuditTrailPopup"), 0);
  284.       cmd.fillParameters(null, "AuditTrailPopup", "");
  285.       xmlDocument.setData("reportAD_User_ID", "liststructure", cmd.select(false));
  286.     } catch (Exception e) {
  287.       log4j.error("Error getting adUser combo content", e);
  288.     }
  289.  
  290.     // fields combobox (filtered to be in same tab)
  291.     try {
  292.       // ad_reference.19 == TableDir
  293.       ComboTableData cmd = new ComboTableData(vars, this, "19", "AD_Field_ID", "",
  294.           adValRuleIdForFields, Utility.getContext(this, vars, "#AccessibleOrgTree",
  295.               "AuditTrailPopup"),
  296.           Utility.getContext(this, vars, "#User_Client", "AuditTrailPopup"), 0);
  297.       SQLReturnObject params = new SQLReturnObject();
  298.       params.setData("AD_Tab_ID", tabId); // parameter for the validation
  299.       cmd.fillParameters(params, "AuditTrailPopup", "");
  300.       xmlDocument.setData("reportAD_Field_ID", "liststructure", cmd.select(false));
  301.     } catch (Exception e) {
  302.       log4j.error("Error getting adField combo content", e);
  303.     }
  304.  
  305.     String recordStatus;
  306.     String identifier;
  307.     Table table = OBDal.getInstance().get(Table.class, tableId);
  308.  
  309.     // popup called from a record or empty grid?
  310.     if (recordId.isEmpty()) {
  311.       recordStatus = "AUDIT_HISTORY_RECORD_NONE";
  312.       identifier = "";
  313.     } else {
  314.       // called with a recordId
  315.       // fill current record status/data table
  316.       BaseOBObject bob = OBDal.getInstance().get(table.getName(), recordId);
  317.       if (bob != null) {
  318.         // for existing records we use the current identifier
  319.         recordStatus = "AUDIT_HISTORY_RECORD_EXISTS";
  320.         identifier = StringEscapeUtils.escapeHtml(bob.getIdentifier());
  321.       } else {
  322.         // for deleted record we build the identifier manually
  323.         recordStatus = "AUDIT_HISTORY_RECORD_DELETED";
  324.         Entity tableEntity = ModelProvider.getInstance().getEntity(table.getName());
  325.         identifier = try2GetIdentifierViaPK(vars, tableEntity, recordId);
  326.       }
  327.     }
  328.  
  329.     // name of the business element shown (i.e. Business Partner)
  330.     String elementNameDisplay = getElementNameForTable(table, OBContext.getOBContext()
  331.         .getLanguage());
  332.  
  333.     String text = Utility.messageBD(this, recordStatus, vars.getLanguage());
  334.     text = text.replace("@recordidentifier@", identifier);
  335.     text = text.replace("@elementname@", elementNameDisplay);
  336.  
  337.     xmlDocument.setParameter("recordIdentifierText", text);
  338.  
  339.     String excludeAuditColumnNames = getExcludeAuditColumnNames(vars, tableId);
  340.     if (excludeAuditColumnNames.length() > 0) {
  341.       String auditText = Utility.messageBD(this, "AUDIT_HISTORY_EXCLUDE_AUDITCOLUMNS",
  342.           vars.getLanguage());
  343.       auditText = auditText.replace("@excludeauditcolumns@", excludeAuditColumnNames);
  344.       xmlDocument.setParameter("excludeAuditColumnText", auditText);
  345.     } else {
  346.       xmlDocument.setParameter("excludeAuditColumnText", "");
  347.     }
  348.  
  349.     // param for building 'View deleted records' link
  350.     xmlDocument.setParameter("recordId", recordId);
  351.     xmlDocument.setParameter("tabId", tabId);
  352.     xmlDocument.setParameter("tableId", tableId);
  353.  
  354.     response.setContentType("text/html; charset=UTF-8");
  355.     PrintWriter out = response.getWriter();
  356.     out.println(xmlDocument.print());
  357.     out.close();
  358.   }
  359.  
  360.   /**
  361.    * Gets the translated name of the business element stored in a table.
  362.    *
  363.    * Done by a lookup of <tableName>+'_ID' in ad_element and ad_element_trl.
  364.    */
  365.   private String getElementNameForTable(Table table, Language language) {
  366.     // name of the business element shown (i.e. Business Partner)
  367.     String elementName = table.getDBTableName() + "_ID";
  368.     String elementNameDisplay;
  369.     String hql = "as e where upper(e.dBColumnName) = :elementName";
  370.     OBQuery<Element> qe = OBDal.getInstance().createQuery(Element.class, hql);
  371.     qe.setNamedParameter("elementName", elementName.toUpperCase());
  372.     List<Element> lElem = qe.list();
  373.     if (lElem.isEmpty()) {
  374.       elementNameDisplay = "(deleted)";
  375.     } else {
  376.       elementNameDisplay = getTranslatedElementName(lElem.get(0), OBContext.getOBContext()
  377.           .getLanguage());
  378.     }
  379.     return elementNameDisplay;
  380.   }
  381.  
  382.   private String getTranslatedElementName(Element element, Language language) {
  383.     OBCriteria<ElementTrl> c = OBDal.getInstance().createCriteria(ElementTrl.class);
  384.     c.add(Restrictions.eq(ElementTrl.PROPERTY_APPLICATIONELEMENT, element));
  385.     c.add(Restrictions.eq(ElementTrl.PROPERTY_LANGUAGE, language));
  386.     ElementTrl trl = (ElementTrl) c.uniqueResult();
  387.     if (trl == null) {
  388.       return element.getName();
  389.     }
  390.     return trl.getName();
  391.   }
  392.  
  393.   private void printPagePopupDeleted(HttpServletResponse response, VariablesSecureApp vars,
  394.       String recordId, String tabId, String tableId) throws IOException, ServletException {
  395.     log4j.debug("POPUP_DELETED - recordId: " + recordId + ", tabId: " + tabId + ", tableId: "
  396.         + tableId);
  397.  
  398.     // first check, if this is an open following a history -> deleted link? or a follow into a child
  399.     // tab link from the deleted records view
  400.     String parentLinkFilter = vars.getStringParameter("inpParentLinkFilter", IsIDFilter.instance);
  401.     boolean haveParentLink = (parentLinkFilter != null && !parentLinkFilter.isEmpty());
  402.     List<String> discards = new ArrayList<String>();
  403.     if (haveParentLink) {
  404.       discards.add("discardLinkBack");
  405.     }
  406.  
  407.     // check if child-tabs exists and build links below the grid
  408.     AuditTrailPopupData[] childTabs = AuditTrailPopupData.selectSubtabs(this, tabId);
  409.     StringBuilder links = new StringBuilder();
  410.     if (childTabs.length == 0) {
  411.       discards.add("childTabsLinksArea");
  412.     } else {
  413.       links.append(Utility.messageBD(this, "AUDIT_HISTORY_CHILDTAB_TEXT", vars.getLanguage()));
  414.       links.append(' ');
  415.       for (AuditTrailPopupData childTab : childTabs) {
  416.         Tab cTab = OBDal.getInstance().get(Tab.class, childTab.tabid);
  417.         String translatedTabName = getTranslatedTabName(cTab);
  418.         String childTableId = cTab.getTable().getId();
  419.         String oneLink = "<a class=\"LabelLink_noicon\" href=\"#\" onclick=\"gotoChild('"
  420.             + childTab.tabid + "', '" + childTableId + "'); return false;\">" + translatedTabName
  421.             + "</a>";
  422.         links.append(oneLink).append(", ");
  423.       }
  424.       links.setLength(links.length() - 2);
  425.     }
  426.     String[] discard = new String[discards.size()];
  427.     discards.toArray(discard);
  428.     XmlDocument xmlDocument = xmlEngine.readXmlTemplate(
  429.         "org/openbravo/erpCommon/businessUtility/AuditTrailPopupDeleted", discard)
  430.         .createXmlDocument();
  431.  
  432.     xmlDocument.setParameter("childTabsLinksArea", links.toString());
  433.  
  434.     xmlDocument.setParameter("directory", "var baseDirectory = \"" + strReplaceWith + "/\";\n");
  435.     xmlDocument.setParameter("language", "defaultLang=\"" + vars.getLanguage() + "\";");
  436.     // calendar language has extra parameter
  437.     xmlDocument.setParameter("calendar", vars.getLanguage().substring(0, 2));
  438.     xmlDocument.setParameter("theme", vars.getTheme());
  439.  
  440.     xmlDocument.setParameter("jsFocusOnField", Utility.focusFieldJS("paramDateFrom"));
  441.  
  442.     xmlDocument.setParameter("grid", "20");
  443.     xmlDocument.setParameter("grid_Offset", "");
  444.     xmlDocument.setParameter("grid_SortCols", "1");
  445.     xmlDocument.setParameter("grid_SortDirs", "DESC");
  446.     xmlDocument.setParameter("grid_Default", "0");
  447.  
  448.     // display/save-formats for the datetime fields
  449.     xmlDocument
  450.         .setParameter("dateFromdisplayFormat", vars.getSessionValue("#AD_SqlDateTimeFormat"));
  451.     xmlDocument.setParameter("dateFromsaveFormat", vars.getSessionValue("#AD_SqlDateTimeFormat"));
  452.     xmlDocument.setParameter("dateTodisplayFormat", vars.getSessionValue("#AD_SqlDateTimeFormat"));
  453.     xmlDocument.setParameter("dateTosaveFormat", vars.getSessionValue("#AD_SqlDateTimeFormat"));
  454.  
  455.     // user combobox (restricted to login users only)
  456.     try {
  457.       ComboTableData cmd = new ComboTableData(vars, this, "19", "AD_User_ID", "",
  458.           "C48E4CAE3C2A4C5DBC2E011D8AD2C428", Utility.getContext(this, vars, "#AccessibleOrgTree",
  459.               "AuditTrailPopup"),
  460.           Utility.getContext(this, vars, "#User_Client", "AuditTrailPopup"), 0);
  461.       cmd.fillParameters(null, "AuditTrailPopup", "");
  462.       xmlDocument.setData("reportAD_User_ID", "liststructure", cmd.select(false));
  463.     } catch (Exception e) {
  464.       log4j.error("Error getting adUser combo content", e);
  465.     }
  466.  
  467.     // param for building 'Back to history' link
  468.     xmlDocument.setParameter("recordId", recordId);
  469.     xmlDocument.setParameter("tabId", tabId);
  470.     xmlDocument.setParameter("tableId", tableId);
  471.  
  472.     // check if opened from a non-toplevel tab, if so then filter by parent record
  473.     // in both cases add message to info area, telling the user about filter/no-filter
  474.     Tab tab = OBDal.getInstance().get(Tab.class, tabId);
  475.     String parentTabId = AuditTrailPopupData.selectParentTab(myPool, tabId);
  476.     if (parentTabId == null) {
  477.       // top-level tab
  478.       log4j.debug("Deleted records view opened for top-level tab");
  479.       String text = Utility
  480.           .messageBD(this, "AUDIT_HISTORY_DELETED_TOPLEVELTAB", vars.getLanguage());
  481.       String elementCurrentTab = getElementNameForTable(tab.getTable(), OBContext.getOBContext()
  482.           .getLanguage());
  483.       text = text.replace("@elementnameCurrentTab@", elementCurrentTab);
  484.       xmlDocument.setParameter("recordIdentifierText", text);
  485.  
  486.       // exclude audit column names in info bar
  487.       String excludeAuditColumnNames = getExcludeAuditColumnNames(vars, tableId);
  488.       if (excludeAuditColumnNames.length() > 0) {
  489.         String auditText = Utility.messageBD(this, "AUDIT_HISTORY_EXCLUDE_AUDITCOLUMNS",
  490.             vars.getLanguage());
  491.         auditText = auditText.replace("@excludeauditcolumns@", excludeAuditColumnNames);
  492.         xmlDocument.setParameter("excludeAuditColumnText", auditText);
  493.       } else {
  494.         xmlDocument.setParameter("excludeAuditColumnText", "");
  495.       }
  496.  
  497.     } else {
  498.       // child-tab of another tab
  499.       Tab parentTab = OBDal.getInstance().get(Tab.class, parentTabId);
  500.       log4j.debug("Deleted records view opened for child tab. Parent is: " + parentTabId);
  501.  
  502.       // code taken from wad to get the columns linking to the parent tab
  503.       AuditTrailPopupData[] parentsFieldsData;
  504.       parentsFieldsData = AuditTrailPopupData.parentsColumnName(this, parentTabId, tabId);
  505.  
  506.       if (parentsFieldsData == null || parentsFieldsData.length == 0) {
  507.         parentsFieldsData = AuditTrailPopupData.parentsColumnReal(this, parentTabId, tabId);
  508.       }
  509.       // according to wad-generated windows, should only be a single field
  510.       if (parentsFieldsData != null && parentsFieldsData.length > 0) {
  511.         AuditTrailPopupData atpd = parentsFieldsData[0];
  512.  
  513.         // followed child link?
  514.         String parentValue;
  515.         if (!parentLinkFilter.isEmpty()) {
  516.           // use value from incoming request
  517.           parentValue = parentLinkFilter;
  518.           log4j
  519.               .debug("Link to parent - columnName: " + atpd.name + " requestValue: " + parentValue);
  520.         } else {
  521.           // try to get value from session
  522.           String windowId = tab.getWindow().getId();
  523.           String sessionVar = windowId + "|" + atpd.name;
  524.           parentValue = vars.getSessionValue(sessionVar);
  525.           log4j
  526.               .debug("Link to parent - columnName: " + atpd.name + " sessionValue: " + parentValue);
  527.         }
  528.  
  529.         // name of the business element shown (i.e. Business Partner)
  530.         String elementCurrentTab = getElementNameForTable(tab.getTable(), OBContext.getOBContext()
  531.             .getLanguage());
  532.         String elementParentTab = getElementNameForTable(parentTab.getTable(), OBContext
  533.             .getOBContext().getLanguage());
  534.  
  535.         // get identifier for current record in parent tab (existing or deleted record)
  536.         String parentIdentifier;
  537.         BaseOBObject bob = OBDal.getInstance().get(parentTab.getTable().getName(), parentValue);
  538.         if (bob != null) {
  539.           parentIdentifier = bob.getIdentifier();
  540.         } else {
  541.           Entity tableEntity = ModelProvider.getInstance()
  542.               .getEntity(parentTab.getTable().getName());
  543.           parentIdentifier = try2GetIdentifierViaPK(vars, tableEntity, parentValue);
  544.         }
  545.  
  546.         String text = Utility.messageBD(this, "AUDIT_HISTORY_DELETED_CHILDTAB", vars.getLanguage());
  547.         text = text.replace("@elementnameCurrentTab@", elementCurrentTab);
  548.         text = text.replace("@elementnameParentTab@", elementParentTab);
  549.         text = text.replace("@parentIdentifier@", StringEscapeUtils.escapeHtml(parentIdentifier));
  550.  
  551.         xmlDocument.setParameter("recordIdentifierText", text);
  552.  
  553.         // exclude audit column names in info bar
  554.         String excludeAuditColumnNames = getExcludeAuditColumnNames(vars, tableId);
  555.         if (excludeAuditColumnNames.length() > 0) {
  556.           String auditText = Utility.messageBD(this, "AUDIT_HISTORY_EXCLUDE_AUDITCOLUMNS",
  557.               vars.getLanguage());
  558.           auditText = auditText.replace("@excludeauditcolumns@", excludeAuditColumnNames);
  559.           xmlDocument.setParameter("excludeAuditColumnText", auditText);
  560.         } else {
  561.           xmlDocument.setParameter("excludeAuditColumnText", "");
  562.         }
  563.  
  564.         // save values for use in DATA request
  565.         vars.setSessionValue("AuditTrail.fkColumnName", atpd.name);
  566.         vars.setSessionValue("AuditTrail.fkId", parentValue);
  567.       }
  568.     }
  569.  
  570.     response.setContentType("text/html; charset=UTF-8");
  571.     PrintWriter out = response.getWriter();
  572.     out.println(xmlDocument.print());
  573.     out.close();
  574.   }
  575.  
  576.   private void printGridStructureHistory(HttpServletResponse response, VariablesSecureApp vars)
  577.       throws IOException, ServletException {
  578.     SQLReturnObject[] data = getHeadersHistory(vars);
  579.     printGridStructureGeneric(data, response, vars);
  580.   }
  581.  
  582.   private SQLReturnObject[] getHeadersHistory(VariablesSecureApp vars) {
  583.     SQLReturnObject[] data = new SQLReturnObject[colNamesHistory.length];
  584.     boolean[] colSortable = { false, false, false, false, false, false, false, true };
  585.     String[] colWidths = { "120", "60", "60", "120", "96", "150", "150", "0" };
  586.     for (int i = 0; i < colNamesHistory.length; i++) {
  587.       SQLReturnObject dataAux = new SQLReturnObject();
  588.       dataAux.setData("columnname", colNamesHistory[i]);
  589.       dataAux.setData("gridcolumnname", colNamesHistory[i]);
  590.       dataAux.setData("isidentifier", (colNamesHistory[i].equals("rowkey") ? "true" : "false"));
  591.       dataAux.setData("iskey", (colNamesHistory[i].equals("rowkey") ? "true" : "false"));
  592.       dataAux.setData("isvisible",
  593.           (colNamesHistory[i].endsWith("_id") || colNamesHistory[i].equals("rowkey") ? "false"
  594.               : "true"));
  595.       String name = Utility.messageBD(this, "AUDIT_HISTORY_" + colNamesHistory[i].toUpperCase(),
  596.           vars.getLanguage());
  597.       dataAux.setData("name", (name.startsWith("AUDIT_HISTORY_") ? colNamesHistory[i] : name));
  598.       dataAux.setData("type", "string");
  599.       dataAux.setData("width", colWidths[i]);
  600.       dataAux.setData("issortable", colSortable[i] ? "true" : "false");
  601.       data[i] = dataAux;
  602.     }
  603.     return data;
  604.   }
  605.  
  606.   private void printGridDataHistory(HttpServletResponse response, VariablesSecureApp vars,
  607.       String tableId, String tabId, String recordId, String userId, String fieldId,
  608.       String strDateFrom, String strDateTo, String strOrderCols, String strOrderDirs,
  609.       String strOffset, String strPageSize, String strNewFilter) throws IOException,
  610.       ServletException {
  611.  
  612.     log4j.debug("DATA_HISTORY: tableId: " + tableId + " recordId: " + recordId);
  613.  
  614.     long s1 = System.currentTimeMillis();
  615.  
  616.     String hql = "as f where f.tab.id = :tabId and (f.displayed = true or f.column.reference.id = '13')";
  617.     OBQuery<Field> qf = OBDal.getInstance().createQuery(Field.class, hql);
  618.     qf.setNamedParameter("tabId", tabId);
  619.     List<Field> fieldList = qf.list();
  620.     Map<String, Field> fields = new HashMap<String, Field>(fieldList.size());
  621.     for (Field f : fieldList) {
  622.       fields.put(f.getColumn().getId(), f);
  623.     }
  624.  
  625.     FieldProvider[] data = null;
  626.     String type = "Hidden";
  627.     String title = "";
  628.     String description = "";
  629.     String strNumRows = "0";
  630.     int offset = Integer.valueOf(strOffset).intValue();
  631.     int pageSize = Integer.valueOf(strPageSize).intValue();
  632.  
  633.     // parse dateTime filter fields
  634.     String strDateFormat = vars.getJavaDataTimeFormat();
  635.     SimpleDateFormat dateFormat = new SimpleDateFormat(strDateFormat);
  636.     Date dateFrom = parseDate(strDateFrom, dateFormat);
  637.     Date dateTo = parseDate(strDateTo, dateFormat);
  638.  
  639.     // get columnId matching the fieldId
  640.     String columnId = "";
  641.     if (fieldId != null && !fieldId.isEmpty()) {
  642.       Field field = OBDal.getInstance().get(Field.class, fieldId);
  643.       columnId = field.getColumn().getId();
  644.     }
  645.  
  646.     try {
  647.       if (strNewFilter.equals("1") || strNewFilter.equals("")) {
  648.         // New filter or first load -> get total rows for filter
  649.         strNumRows = getCountRowsHistory(tableId, fields.keySet(), recordId, userId, columnId,
  650.             dateFrom, dateTo);
  651.         vars.setSessionValue("AuditTrail.numrows", strNumRows);
  652.       } else {
  653.         strNumRows = vars.getSessionValue("AuditTrail.numrows");
  654.       }
  655.  
  656.       // get data (paged by offset, pageSize)
  657.       data = getDataRowsHistory(vars, tableId, tabId, fields, recordId, userId, columnId, dateFrom,
  658.           dateTo, offset, pageSize, vars.getLanguage());
  659.     } catch (ServletException e) {
  660.       log4j.error("Error getting row data: ", e);
  661.       OBError myError = Utility.translateError(this, vars, vars.getLanguage(), e.getMessage());
  662.       if (!myError.isConnectionAvailable()) {
  663.         bdErrorAjax(response, "Error", "Connection Error", "No database connection");
  664.         return;
  665.       } else {
  666.         type = myError.getType();
  667.         title = myError.getTitle();
  668.         if (!myError.getMessage().startsWith("<![CDATA["))
  669.           description = "<![CDATA[" + myError.getMessage() + "]]>";
  670.         else
  671.           description = myError.getMessage();
  672.       }
  673.     } catch (Exception e) {
  674.       log4j.error("Error getting row data: ", e);
  675.       type = "Error";
  676.       title = "Error";
  677.       if (e.getMessage().startsWith("<![CDATA["))
  678.         description = "<![CDATA[" + e.getMessage() + "]]>";
  679.       else
  680.         description = e.getMessage();
  681.     }
  682.  
  683.     if (!type.startsWith("<![CDATA["))
  684.       type = "<![CDATA[" + type + "]]>";
  685.     if (!title.startsWith("<![CDATA["))
  686.       title = "<![CDATA[" + title + "]]>";
  687.     if (!description.startsWith("<![CDATA["))
  688.       description = "<![CDATA[" + description + "]]>";
  689.     StringBuffer strRowsData = new StringBuffer();
  690.     strRowsData.append("<xml-data>\n");
  691.     strRowsData.append("  <status>\n");
  692.     strRowsData.append("    <type>").append(type).append("</type>\n");
  693.     strRowsData.append("    <title>").append(title).append("</title>\n");
  694.     strRowsData.append("    <description>").append(description).append("</description>\n");
  695.     strRowsData.append("  </status>\n");
  696.     strRowsData.append("  <rows numRows=\"").append(strNumRows).append("\">\n");
  697.     if (data != null && data.length > 0) {
  698.       for (int j = 0; j < data.length; j++) {
  699.         strRowsData.append("    <tr>\n");
  700.         for (String columnname : colNamesHistory) {
  701.           strRowsData.append("      <td><![CDATA[");
  702.           // formatting already done
  703.           strRowsData.append(data[j].getField(columnname));
  704.           strRowsData.append("]]></td>\n");
  705.         }
  706.         strRowsData.append("    </tr>\n");
  707.       }
  708.     }
  709.     strRowsData.append("  </rows>\n");
  710.     strRowsData.append("</xml-data>\n");
  711.  
  712.     response.setContentType("text/xml; charset=UTF-8");
  713.     response.setHeader("Cache-Control", "no-cache");
  714.     PrintWriter out = response.getWriter();
  715.     out.print(strRowsData.toString());
  716.     out.close();
  717.     long s2 = System.currentTimeMillis();
  718.     log4j.debug("printGridDataHistory took: " + (s2 - s1));
  719.   }
  720.  
  721.   private String getCountRowsHistory(String tableId, Collection<String> columnIds, String recordId,
  722.       String userId, String columnId, Date dateFrom, Date dateTo) {
  723.     long s1 = System.currentTimeMillis();
  724.  
  725.     OBCriteria<AuditTrailRaw> crit = OBDal.getInstance().createCriteria(AuditTrailRaw.class);
  726.     crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_TABLE, tableId));
  727.     crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_RECORDID, recordId));
  728.     // filter to only show rows which have their column shown in the tab
  729.     crit.add(Restrictions.in(AuditTrailRaw.PROPERTY_COLUMN, columnIds));
  730.     if (!userId.isEmpty()) {
  731.       crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_USERCONTACT, userId));
  732.     }
  733.     if (!columnId.isEmpty()) {
  734.       crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_COLUMN, columnId));
  735.     }
  736.     if (dateFrom != null) {
  737.       crit.add(Restrictions.ge(AuditTrailRaw.PROPERTY_EVENTTIME, dateFrom));
  738.     }
  739.     if (dateTo != null) {
  740.       crit.add(Restrictions.le(AuditTrailRaw.PROPERTY_EVENTTIME, dateTo));
  741.     }
  742.     int count = crit.count();
  743.  
  744.     long s2 = System.currentTimeMillis();
  745.     log4j.debug("getCountRowsHistory took: " + (s2 - s1) + " result= " + count);
  746.  
  747.     return String.valueOf(count);
  748.   }
  749.  
  750.   private FieldProvider[] getDataRowsHistory(VariablesSecureApp vars, String tableId, String tabId,
  751.       Map<String, Field> tabFields, String recordId, String userId, String columnId, Date dateFrom,
  752.       Date dateTo, int offset, int pageSize, String language) throws ServletException {
  753.  
  754.     OBCriteria<AuditTrailRaw> crit = OBDal.getInstance().createCriteria(AuditTrailRaw.class);
  755.     crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_TABLE, tableId));
  756.     crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_RECORDID, recordId));
  757.     // filter to only show rows which have their column shown in the tab
  758.     crit.add(Restrictions.in(AuditTrailRaw.PROPERTY_COLUMN, tabFields.keySet()));
  759.     crit.addOrder(Order.desc(AuditTrailRaw.PROPERTY_EVENTTIME));
  760.     if (!userId.isEmpty()) {
  761.       crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_USERCONTACT, userId));
  762.     }
  763.     if (!columnId.isEmpty()) {
  764.       crit.add(Restrictions.eq(AuditTrailRaw.PROPERTY_COLUMN, columnId));
  765.     }
  766.     if (dateFrom != null) {
  767.       crit.add(Restrictions.ge(AuditTrailRaw.PROPERTY_EVENTTIME, dateFrom));
  768.     }
  769.     if (dateTo != null) {
  770.       crit.add(Restrictions.le(AuditTrailRaw.PROPERTY_EVENTTIME, dateTo));
  771.     }
  772.     crit.setFirstResult(offset);
  773.     crit.setMaxResults(pageSize);
  774.     List<AuditTrailRaw> rows = crit.list();
  775.  
  776.     /*
  777.      * beautify result logic is kept simple: iterate over main query result and do needed extra
  778.      * queries to get the beautified column output pro: - simple, keep criteria for main query
  779.      * instead of manual hql . with hibernate session cache: query per distinct pk value only con: -
  780.      * subqueries for column beautification instead of a bigger main query
  781.      */
  782.     UtilityData[] actions = UtilityData.selectReference(this, language, auditActionsReferenceId);
  783.  
  784.     List<SQLReturnObject> resRows = new ArrayList<SQLReturnObject>(rows.size());
  785.     for (AuditTrailRaw row : rows) {
  786.       SQLReturnObject resRow = new SQLReturnObject();
  787.       resRow.setData("time", getFormattedTime(vars, row.getEventTime()));
  788.       resRow.setData("action", getFormattedAction(actions, row.getAction()));
  789.       resRow.setData("user", getFormattedUser(vars, row.getUserContact()));
  790.       resRow.setData("process", getFormattedProcess(row.getProcessType(), row.getProcess()));
  791.       resRow.setData("field", getFormattedField(tabFields, row));
  792.       resRow.setData("old_value", getFormattedValue(vars, row, false));
  793.       resRow.setData("new_value", getFormattedValue(vars, row, true));
  794.       resRow.setData("rowkey", row.getId());
  795.       resRows.add(resRow);
  796.     }
  797.  
  798.     FieldProvider[] res = new FieldProvider[resRows.size()];
  799.     res = resRows.toArray(res);
  800.     return res;
  801.   }
  802.  
  803.   private void printGridStructureDeleted(HttpServletResponse response, VariablesSecureApp vars,
  804.       String tabId, String tableId) throws IOException, ServletException {
  805.     SQLReturnObject[] data = getHeadersDeleted(vars, tabId, tableId);
  806.     printGridStructureGeneric(data, response, vars);
  807.   }
  808.  
  809.   private SQLReturnObject[] getHeadersDeleted(VariablesSecureApp vars, String tabId, String tableId) {
  810.  
  811.     List<SQLReturnObject> data = new ArrayList<SQLReturnObject>();
  812.  
  813.     // rowkey
  814.     SQLReturnObject gridCol = new SQLReturnObject();
  815.     gridCol.setData("columnname", "rowkey");
  816.     gridCol.setData("gridcolumnname", "rowkey");
  817.     gridCol.setData("isidentifier", "true");
  818.     gridCol.setData("iskey", "true");
  819.     gridCol.setData("isvisible", "false");
  820.     gridCol.setData("name", "rowkey");
  821.     gridCol.setData("type", "string");
  822.     gridCol.setData("width", "0");
  823.     gridCol.setData("issortable", "true");
  824.     data.add(gridCol);
  825.  
  826.     // time
  827.     gridCol = new SQLReturnObject();
  828.     gridCol.setData("columnname", "audittrailtime");
  829.     gridCol.setData("gridcolumnname", "audittrailtime");
  830.     gridCol.setData("isidentifier", "false");
  831.     gridCol.setData("iskey", "false");
  832.     gridCol.setData("isvisible", "true");
  833.     String translatedName = Utility.messageBD(this, "AUDIT_HISTORY_TIME", vars.getLanguage());
  834.     gridCol.setData("name", translatedName);
  835.     gridCol.setData("type", "string");
  836.     gridCol.setData("width", "120");
  837.     gridCol.setData("issortable", "true");
  838.     data.add(gridCol);
  839.  
  840.     // user
  841.     gridCol = new SQLReturnObject();
  842.     gridCol.setData("columnname", "audittrailuser");
  843.     gridCol.setData("gridcolumnname", "audittrailuser");
  844.     gridCol.setData("isidentifier", "false");
  845.     gridCol.setData("iskey", "false");
  846.     gridCol.setData("isvisible", "true");
  847.     translatedName = Utility.messageBD(this, "AUDIT_HISTORY_USER", vars.getLanguage());
  848.     gridCol.setData("name", translatedName);
  849.     gridCol.setData("type", "string");
  850.     gridCol.setData("width", "60");
  851.     gridCol.setData("issortable", "false");
  852.     data.add(gridCol);
  853.  
  854.     // process
  855.     gridCol = new SQLReturnObject();
  856.     gridCol.setData("columnname", "audittrailprocess");
  857.     gridCol.setData("gridcolumnname", "audittrailprocess");
  858.     gridCol.setData("isidentifier", "false");
  859.     gridCol.setData("iskey", "false");
  860.     gridCol.setData("isvisible", "true");
  861.     translatedName = Utility.messageBD(this, "AUDIT_HISTORY_PROCESS", vars.getLanguage());
  862.     gridCol.setData("name", translatedName);
  863.     gridCol.setData("type", "string");
  864.     gridCol.setData("width", "120");
  865.     gridCol.setData("issortable", "false");
  866.     data.add(gridCol);
  867.  
  868.     Tab tab = OBDal.getInstance().get(Tab.class, tabId);
  869.     List<Field> fields = getFieldListForTab(vars, tab);
  870.     for (Field field : fields) {
  871.       Column col = field.getColumn();
  872.       // Remove grid generation for non audited columns
  873.       if (col == null || col.isExcludeAudit()) {
  874.         continue;
  875.       }
  876.       gridCol = new SQLReturnObject();
  877.       gridCol.setData("columnname", col.getDBColumnName());
  878.       gridCol.setData("gridcolumnname", col.getDBColumnName());
  879.       gridCol.setData("isidentifier", "false");
  880.       gridCol.setData("iskey", "false");
  881.       gridCol.setData("isvisible", "true");
  882.  
  883.       // TODO: optimize fetch for translation
  884.       gridCol
  885.           .setData("name", getTranslatedFieldName(field, OBContext.getOBContext().getLanguage()));
  886.       gridCol.setData("type", "string");
  887.  
  888.       gridCol.setData("width", calculateColumnWidth(field.getDisplayedLength()));
  889.       gridCol.setData("issortable", "false");
  890.       data.add(gridCol);
  891.     }
  892.  
  893.     SQLReturnObject[] result = new SQLReturnObject[data.size()];
  894.     data.toArray(result);
  895.     return result;
  896.   }
  897.  
  898.   /**
  899.    * Get the ordered list of fields shown in a grid view of a specific tab.
  900.    */
  901.   private List<Field> getFieldListForTab(VariablesSecureApp vars, Tab tab) {
  902.     OBCriteria<Field> c = OBDal.getInstance().createCriteria(Field.class);
  903.     c.add(Restrictions.eq(Field.PROPERTY_TAB, tab));
  904.     c.add(Restrictions.eq(Field.PROPERTY_DISPLAYED, Boolean.TRUE));
  905.     c.add(Restrictions.eq(Field.PROPERTY_SHOWINGRIDVIEW, Boolean.TRUE));
  906.     c.setFetchMode("column", FetchMode.JOIN); // optimize column association
  907.     c.addOrderBy(Field.PROPERTY_SEQUENCENUMBER, true);
  908.     List<Field> fields = c.list();
  909.     return fields;
  910.   }
  911.  
  912.   private String getTranslatedFieldName(Field field, Language lang) {
  913.     OBCriteria<FieldTrl> c = OBDal.getInstance().createCriteria(FieldTrl.class);
  914.     c.add(Restrictions.eq(FieldTrl.PROPERTY_FIELD, field));
  915.     c.add(Restrictions.eq(FieldTrl.PROPERTY_LANGUAGE, lang));
  916.     FieldTrl trl = (FieldTrl) c.uniqueResult();
  917.     if (trl == null) {
  918.       return field.getName();
  919.     }
  920.     return trl.getName();
  921.   }
  922.  
  923.   /**
  924.    * Utility method to translate a displayLenth into a column width (in a DataGrid).
  925.    *
  926.    * Logic needs to be synchronized with TableSQLData.getHeaders
  927.    */
  928.   private String calculateColumnWidth(Long displayLength) {
  929.     long width = displayLength * 6;
  930.     // cap with interval [23..300]
  931.     width = Math.max(23, width);
  932.     width = Math.min(300, width);
  933.     return String.valueOf(width);
  934.   }
  935.  
  936.   private void printGridDataDeleted(HttpServletResponse response, VariablesSecureApp vars,
  937.       String tabId, String tableId, String strDateFrom, String strDateTo, String userId,
  938.       String strOrderCols, String strOrderDirs, String strOffset, String strPageSize,
  939.       String strNewFilter) throws IOException, ServletException {
  940.  
  941.     long s1 = System.currentTimeMillis();
  942.     SQLReturnObject[] headers = getHeadersDeleted(vars, tabId, tableId);
  943.     FieldProvider[] data = null;
  944.     String type = "Hidden";
  945.     String title = "";
  946.     String description = "";
  947.     String strNumRows = "0";
  948.     int offset = Integer.valueOf(strOffset).intValue();
  949.     int pageSize = Integer.valueOf(strPageSize).intValue();
  950.  
  951.     // read optional values for parent filter
  952.     String fkColumnName = vars.getSessionValue("AuditTrail.fkColumnName");
  953.     String fkId = vars.getSessionValue("AuditTrail.fkId");
  954.  
  955.     try {
  956.       if (strNewFilter.equals("1") || strNewFilter.equals("")) {
  957.         // New filter or first load
  958.         strNumRows = getCountRowsDeleted(vars, tabId, tableId, fkColumnName, fkId, offset,
  959.             pageSize, strDateFrom, strDateTo, userId);
  960.         vars.setSessionValue("AuditTrail.numrows", strNumRows);
  961.       } else {
  962.         strNumRows = vars.getSessionValue("AuditTrail.numrows");
  963.       }
  964.  
  965.       // get data
  966.       data = getDataRowsDeleted(vars, tabId, tableId, fkColumnName, fkId, offset, pageSize,
  967.           strDateFrom, strDateTo, userId);
  968.     } catch (Exception e) {
  969.       log4j.error("Error getting row data: ", e);
  970.       type = "Error";
  971.       title = "Error";
  972.       if (e.getMessage().startsWith("<![CDATA["))
  973.         description = "<![CDATA[" + e.getMessage() + "]]>";
  974.       else
  975.         description = e.getMessage();
  976.     }
  977.  
  978.     if (!type.startsWith("<![CDATA["))
  979.       type = "<![CDATA[" + type + "]]>";
  980.     if (!title.startsWith("<![CDATA["))
  981.       title = "<![CDATA[" + title + "]]>";
  982.     if (!description.startsWith("<![CDATA["))
  983.       description = "<![CDATA[" + description + "]]>";
  984.     StringBuffer strRowsData = new StringBuffer();
  985.     strRowsData.append("<xml-data>\n");
  986.     strRowsData.append("  <status>\n");
  987.     strRowsData.append("    <type>").append(type).append("</type>\n");
  988.     strRowsData.append("    <title>").append(title).append("</title>\n");
  989.     strRowsData.append("    <description>").append(description).append("</description>\n");
  990.     strRowsData.append("  </status>\n");
  991.     strRowsData.append("  <rows numRows=\"").append(strNumRows).append("\">\n");
  992.     if (data != null && data.length > 0) {
  993.       for (int j = 0; j < data.length; j++) {
  994.         strRowsData.append("    <tr>\n");
  995.         for (int k = 0; k < headers.length; k++) {
  996.           strRowsData.append("      <td><![CDATA[");
  997.           String columnname = headers[k].getField("columnname");
  998.  
  999.           String value = data[j].getField(columnname);
  1000.           strRowsData.append(value);
  1001.           strRowsData.append("]]></td>\n");
  1002.         }
  1003.         strRowsData.append("    </tr>\n");
  1004.       }
  1005.     }
  1006.     strRowsData.append("  </rows>\n");
  1007.     strRowsData.append("</xml-data>\n");
  1008.  
  1009.     response.setContentType("text/xml; charset=UTF-8");
  1010.     response.setHeader("Cache-Control", "no-cache");
  1011.     PrintWriter out = response.getWriter();
  1012.     out.print(strRowsData.toString());
  1013.     out.close();
  1014.     long s2 = System.currentTimeMillis();
  1015.     log4j.debug("printGridDataDeleted took: " + (s2 - s1));
  1016.   }
  1017.  
  1018.   private String getCountRowsDeleted(VariablesSecureApp vars, String tabId, String tableId,
  1019.       String fkColumnName, String fkId, int offset, int pageSize, String dateFrom, String dateTo,
  1020.       String userId) {
  1021.     long s1 = System.currentTimeMillis();
  1022.     FieldProvider[] rows = AuditTrailDeletedRecords.getDeletedRecords(this, vars, tabId,
  1023.         fkColumnName, fkId, 0, 0, true, dateFrom, dateTo, userId);
  1024.     String countResult = rows[0].getField("counter");
  1025.     long t1 = System.currentTimeMillis();
  1026.  
  1027.     log4j.debug("getCountRowsDeleted took: " + (t1 - s1) + " result= " + countResult);
  1028.     return countResult;
  1029.   }
  1030.  
  1031.   private FieldProvider[] getDataRowsDeleted(VariablesSecureApp vars, String tabId, String tableId,
  1032.       String fkColumnName, String fkId, int offset, int pageSize, String dateFrom, String dateTo,
  1033.       String userId) {
  1034.  
  1035.     long s1 = System.currentTimeMillis();
  1036.     FieldProvider[] rows = AuditTrailDeletedRecords.getDeletedRecords(this, vars, tabId,
  1037.         fkColumnName, fkId, offset, pageSize, false, dateFrom, dateTo, userId);
  1038.     long s2 = System.currentTimeMillis();
  1039.  
  1040.     /*
  1041.      * beautify result logic is kept simple: iterate over main query result and do needed extra
  1042.      * queries to get the beautified column output pro: - simple, keep criteria for main query
  1043.      * instead of manual hql . with hibernate session cache: query per distinct pk value only con: -
  1044.      * subqueries for column beautification instead of a bigger main query
  1045.      */
  1046.     List<FieldProvider> resRows = new ArrayList<FieldProvider>();
  1047.     for (FieldProvider row : rows) {
  1048.       // copy and beautify
  1049.       SQLReturnObject resRow = new SQLReturnObject();
  1050.       Tab tab = OBDal.getInstance().get(Tab.class, tabId);
  1051.       // copy static fields to result
  1052.       resRow.setData("rowkey", row.getField("rowkey"));
  1053.       resRow.setData("audittrailtime", getFormattedTime(vars, row.getField("audittrailtime")));
  1054.       resRow.setData("audittrailuser", getFormattedUser(vars, row.getField("audittrailuser")));
  1055.       resRow.setData(
  1056.           "audittrailprocess",
  1057.           getFormattedProcess(row.getField("audittrailprocesstype"),
  1058.               row.getField("audittrailprocessid")));
  1059.       // copy and beautify data columns
  1060.       for (Field field : tab.getADFieldList()) {
  1061.         // no need to format hidden fields
  1062.         if (!field.isShowInGridView() || !field.isDisplayed()) {
  1063.           continue;
  1064.         }
  1065.         Column col = field.getColumn();
  1066.         if (col == null) {
  1067.           continue;
  1068.         }
  1069.         String value = row.getField(col.getDBColumnName());
  1070.         // beautify it
  1071.         value = getFormattedValue(vars, col, value);
  1072.         resRow.setData(col.getDBColumnName(), value);
  1073.       }
  1074.       resRows.add(resRow);
  1075.  
  1076.     }
  1077.  
  1078.     long s3 = System.currentTimeMillis();
  1079.     log4j.debug("getDataRowsDeleted: getRows:" + (s2 - s1) + " beautifyRows: " + (s3 - s2));
  1080.  
  1081.     FieldProvider[] res = new FieldProvider[resRows.size()];
  1082.     resRows.toArray(res);
  1083.     return res;
  1084.   }
  1085.  
  1086.   /**
  1087.    * Helper function which returns the old value from a audit row. Essentially
  1088.    * coalesce(old_char,old_nchar,old_date,old_number, old_text)
  1089.    *
  1090.    * @param row
  1091.    *          audit record
  1092.    * @return the old value from that row
  1093.    */
  1094.   private static String getOld(AuditTrailRaw row) {
  1095.     String result;
  1096.     result = row.getOldChar();
  1097.     if (result == null) {
  1098.       result = row.getOldNChar();
  1099.     }
  1100.     if (result == null && row.getOldDate() != null) {
  1101.       result = String.valueOf(row.getOldDate());
  1102.     }
  1103.     if (result == null && row.getOldNumber() != null) {
  1104.       result = String.valueOf(row.getOldNumber());
  1105.     }
  1106.     if (result == null && row.getOldText() != null) {
  1107.       result = row.getOldText();
  1108.     }
  1109.     return result;
  1110.   }
  1111.  
  1112.   /**
  1113.    * Helper function which returns the new value from a audit row. Essentially coalesce(new_char,
  1114.    * new_nchar, new_date, new_number, new_text)
  1115.    *
  1116.    * @param row
  1117.    *          audit record
  1118.    * @return the new value from that row
  1119.    */
  1120.   private static String getNew(AuditTrailRaw row) {
  1121.     String result;
  1122.     result = row.getNewChar();
  1123.     if (result == null) {
  1124.       result = row.getNewNChar();
  1125.     }
  1126.     if (result == null && row.getNewDate() != null) {
  1127.       result = String.valueOf(row.getNewDate());
  1128.     }
  1129.     if (result == null && row.getNewNumber() != null) {
  1130.       result = String.valueOf(row.getNewNumber());
  1131.     }
  1132.     if (result == null && row.getNewText() != null) {
  1133.       result = row.getNewText();
  1134.     }
  1135.     return result;
  1136.   }
  1137.  
  1138.   private static String getFormattedTime(VariablesSecureApp vars, Date time) {
  1139.     SimpleDateFormat format = new SimpleDateFormat(vars.getJavaDataTimeFormat());
  1140.     return format.format(time);
  1141.   }
  1142.  
  1143.   // used for deleted records view, time already comes in a sqldatetimeformat
  1144.   private static String getFormattedTime(VariablesSecureApp vars, String time) {
  1145.     // currently no-op
  1146.     return time;
  1147.   }
  1148.  
  1149.   /*
  1150.    * translate action reference value into translated reference list name, as list of distinct
  1151.    * values is small do one query for all outside of the loop
  1152.    */
  1153.   private static String getFormattedAction(final UtilityData[] actions, String action) {
  1154.     for (UtilityData theAction : actions) {
  1155.       if (theAction.value.equals(action)) {
  1156.         return theAction.name;
  1157.       }
  1158.     }
  1159.     return action;
  1160.   }
  1161.  
  1162.   private String getFormattedUser(VariablesSecureApp vars, String userId) {
  1163.     if (userId == null) {
  1164.       return " ";
  1165.     }
  1166.     User u = OBDal.getInstance().get(User.class, userId);
  1167.     if (u != null) {
  1168.       return u.getName();
  1169.     }
  1170.     // get value via deleted record audit data
  1171.     Entity userEntity = ModelProvider.getInstance().getEntity(User.ENTITY_NAME);
  1172.     return try2GetIdentifierViaPK(vars, userEntity, userId);
  1173.   }
  1174.  
  1175.   /**
  1176.    * Map a pair of (processType,process) to a user displayValue by looking up the matching model
  1177.    * object names.
  1178.    *
  1179.    * The definition of processType is taken from org.openbravo.base.secureApp.ClassInfoData.select
  1180.    *
  1181.    * @param processType
  1182.    *          char defining which table the process parameter points to
  1183.    * @param process
  1184.    *          uuid pointing to a model table defined via processType
  1185.    */
  1186.   private String getFormattedProcess(String processType, String process) {
  1187.     if (processType == null || process == null) {
  1188.       return " ";
  1189.     }
  1190.  
  1191.     switch (processType) {
  1192.     case "X":
  1193.       String formLabel = getTranslatedMessage(adMessageIdForForm);
  1194.       return formLabel + ": " + getTranslatedFormName(process);
  1195.     case "P":
  1196.       String processLabel = getTranslatedMessage(adMessageIdForProcess);
  1197.       return processLabel + ": " + getTranslatedProcessName(process);
  1198.     case "S":
  1199.       return "Reference: " + OBDal.getInstance().get(Reference.class, process).getName();
  1200.     case "C":
  1201.       String calloutLabel = getTranslatedMessage(adMessageIdForCallout);
  1202.       return calloutLabel + ": " + OBDal.getInstance().get(Callout.class, process).getName();
  1203.     case "CF":
  1204.       String processCFLabel = getTranslatedMessage(adMessageIdForCF);
  1205.       return processCFLabel + ": " + OBDal.getInstance().get(Table.class, process).getDBTableName();
  1206.     case "PD":
  1207.       String processPDLabel = getTranslatedMessage(adMessageIdForProcess);
  1208.       return processPDLabel + ": "
  1209.           + OBDal.getInstance().get(Process.class, process).getIdentifier();
  1210.     case "W":
  1211.       String windowLabel = getTranslatedMessage(adMessageIdForWindow);
  1212.       return windowLabel + ": " + getTranslatedWindowName(process);
  1213.     default:
  1214.       return getTranslatedMessageByValue(processType)
  1215.           + (!processType.equals(process) ? ": " + getTranslatedMessageByValue(process) : "");
  1216.     }
  1217.   }
  1218.  
  1219.   private String getTranslatedMessageByValue(String value) {
  1220.     OBCriteria<Message> c = OBDal.getInstance().createCriteria(Message.class);
  1221.     c.add(Restrictions.eq(Message.PROPERTY_SEARCHKEY, value));
  1222.     Message msg = (Message) c.uniqueResult();
  1223.     if (msg == null) {
  1224.       return value;
  1225.     }
  1226.     return getTranslatedMessage(msg);
  1227.   }
  1228.  
  1229.   private String getTranslatedMessage(String msgId) {
  1230.     Message msg = OBDal.getInstance().get(Message.class, msgId);
  1231.     if (msg == null) {
  1232.       return msgId;
  1233.     }
  1234.     return getTranslatedMessage(msg);
  1235.   }
  1236.  
  1237.   private String getTranslatedMessage(Message msg) {
  1238.     OBCriteria<MessageTrl> c = OBDal.getInstance().createCriteria(MessageTrl.class);
  1239.     c.add(Restrictions.eq(MessageTrl.PROPERTY_MESSAGE, msg));
  1240.     c.add(Restrictions.eq(MessageTrl.PROPERTY_LANGUAGE, OBContext.getOBContext().getLanguage()));
  1241.     MessageTrl trl = (MessageTrl) c.uniqueResult();
  1242.     if (trl == null) {
  1243.       return msg.getMessageText();
  1244.     }
  1245.     return trl.getMessageText();
  1246.   }
  1247.  
  1248.   private String getTranslatedTabName(Tab tab) {
  1249.     OBCriteria<TabTrl> c = OBDal.getInstance().createCriteria(TabTrl.class);
  1250.     c.add(Restrictions.eq(TabTrl.PROPERTY_TAB, tab));
  1251.     c.add(Restrictions.eq(TabTrl.PROPERTY_LANGUAGE, OBContext.getOBContext().getLanguage()));
  1252.     TabTrl trl = (TabTrl) c.uniqueResult();
  1253.     if (trl == null) {
  1254.       return tab.getName();
  1255.     }
  1256.     return trl.getName();
  1257.   }
  1258.  
  1259.   private String getTranslatedWindowName(String tabId) {
  1260.     Window w = OBDal.getInstance().get(Tab.class, tabId).getWindow();
  1261.     OBCriteria<WindowTrl> c = OBDal.getInstance().createCriteria(WindowTrl.class);
  1262.     c.add(Restrictions.eq(WindowTrl.PROPERTY_WINDOW, w));
  1263.     c.add(Restrictions.eq(WindowTrl.PROPERTY_LANGUAGE, OBContext.getOBContext().getLanguage()));
  1264.     WindowTrl trl = (WindowTrl) c.uniqueResult();
  1265.     if (trl == null) {
  1266.       return w.getName();
  1267.     }
  1268.     return trl.getName();
  1269.   }
  1270.  
  1271.   private String getTranslatedProcessName(String processId) {
  1272.     org.openbravo.model.ad.ui.Process p = OBDal.getInstance().get(
  1273.         org.openbravo.model.ad.ui.Process.class, processId);
  1274.     OBCriteria<ProcessTrl> c = OBDal.getInstance().createCriteria(ProcessTrl.class);
  1275.     c.add(Restrictions.eq(ProcessTrl.PROPERTY_PROCESS, p));
  1276.     c.add(Restrictions.eq(ProcessTrl.PROPERTY_LANGUAGE, OBContext.getOBContext().getLanguage()));
  1277.     ProcessTrl trl = (ProcessTrl) c.uniqueResult();
  1278.     if (trl == null) {
  1279.       return p.getName();
  1280.     }
  1281.     return trl.getName();
  1282.   }
  1283.  
  1284.   private String getTranslatedFormName(String formId) {
  1285.     Form f = OBDal.getInstance().get(Form.class, formId);
  1286.     OBCriteria<FormTrl> c = OBDal.getInstance().createCriteria(FormTrl.class);
  1287.     c.add(Restrictions.eq(FormTrl.PROPERTY_SPECIALFORM, f));
  1288.     c.add(Restrictions.eq(FormTrl.PROPERTY_LANGUAGE, OBContext.getOBContext().getLanguage()));
  1289.     FormTrl trl = (FormTrl) c.uniqueResult();
  1290.     if (trl == null) {
  1291.       return f.getName();
  1292.     }
  1293.     return trl.getName();
  1294.   }
  1295.  
  1296.   // TODO: optimize trl fetching
  1297.   private String getFormattedField(Map<String, Field> tabFields, AuditTrailRaw auditRow) {
  1298.     Field field = tabFields.get(auditRow.getColumn());
  1299.  
  1300.     String fieldNameTranslated = getTranslatedFieldName(field, OBContext.getOBContext()
  1301.         .getLanguage());
  1302.     return fieldNameTranslated;
  1303.   }
  1304.  
  1305.   private String getFormattedValue(VariablesSecureApp vars, AuditTrailRaw auditRow, boolean newValue) {
  1306.     String value = newValue ? getNew(auditRow) : getOld(auditRow);
  1307.     Column col = OBDal.getInstance().get(Column.class, auditRow.getColumn());
  1308.     return getFormattedValue(vars, col, value);
  1309.   }
  1310.  
  1311.   private String getFormattedValue(VariablesSecureApp vars, Column col, String value) {
  1312.     if (col == null) {
  1313.       // column might have been deleted in the model
  1314.       return value;
  1315.     }
  1316.  
  1317.     // no need to follow a null into some reference
  1318.     if (value == null) {
  1319.       // translate null into an empty String for display
  1320.       return " ";
  1321.     }
  1322.  
  1323.     Table table = col.getTable();
  1324.     Entity tableEntity = ModelProvider.getInstance().getEntity(table.getName());
  1325.  
  1326.     String referenceName = col.getReference().getName();
  1327.  
  1328.     Property colProperty = tableEntity.getPropertyByColumnName(col.getDBColumnName());
  1329.     Entity targetEntity = colProperty.getTargetEntity();
  1330.     Property referencedCp = colProperty.getReferencedProperty();
  1331.  
  1332.     // cannot be handled by generic targetEntity/referencedProperty code below
  1333.     if (referenceName.equals("List")) {
  1334.       Reference colListRef = col.getReferenceSearchKey();
  1335.       return getTranslatedListValueName(colListRef, value);
  1336.     }
  1337.  
  1338.     // generic handling of fk-lookup via targetEntity/referencedProperty
  1339.     // handles Table,TableDir,Search for now, and all new reference types providing
  1340.     // targetEntity/referencedProperty
  1341.     if (targetEntity != null) {
  1342.       // try generic lookup or fk-target value
  1343.       if (referencedCp == null) {
  1344.         // use targetEntity's pk as lookup key (like in TableDir case)
  1345.         return getFkTargetIdentifierViaPK(vars, targetEntity, value);
  1346.       }
  1347.       return getFkTargetIdentifierViaReferencedColumn(vars, targetEntity, referencedCp, value);
  1348.     }
  1349.  
  1350.     // format all other value according to their defined reference
  1351.     String adReferenceId = col.getReference().getId();
  1352.     UIReference reference = org.openbravo.reference.Reference.getUIReference(adReferenceId,
  1353.         adReferenceId);
  1354.     return reference.formatGridValue(vars, value);
  1355.   }
  1356.  
  1357.   /**
  1358.    * Returns the identifier for a given Entity,pk-value combination. If the target record cannot be
  1359.    * found, a lookup of the record in the deleted audit-data is performed.
  1360.    */
  1361.   private String getFkTargetIdentifierViaPK(VariablesSecureApp vars, Entity targetEntity,
  1362.       String fkValue) {
  1363.     BaseOBObject bob = OBDal.getInstance().get(targetEntity.getName(), fkValue);
  1364.     if (bob != null) {
  1365.       return bob.getIdentifier();
  1366.     }
  1367.     // try to get identifier from audit data
  1368.     return try2GetIdentifierViaPK(vars, targetEntity, fkValue);
  1369.   }
  1370.  
  1371.   /**
  1372.    * Returns the identifier for a given Entity,fk-field,fk-field-value combination. If the target
  1373.    * record cannot be found, a lookup of the record in the deleted audit-data is performed.
  1374.    */
  1375.   private String getFkTargetIdentifierViaReferencedColumn(VariablesSecureApp vars,
  1376.       Entity targetEntity, Property referencedProperty, String value) {
  1377.     OBCriteria<BaseOBObject> c = OBDal.getInstance().createCriteria(targetEntity.getName());
  1378.     c.add(Restrictions.eq(referencedProperty.getName(), value));
  1379.     BaseOBObject bob = (BaseOBObject) c.uniqueResult();
  1380.     if (bob != null) {
  1381.       return bob.getIdentifier();
  1382.     }
  1383.     // try to get identifier from audit data
  1384.     return try2GetIdentifierViaReferencedColumn(vars, targetEntity, referencedProperty, value);
  1385.   }
  1386.  
  1387.   private String try2GetIdentifierViaReferencedColumn(VariablesSecureApp vars, Entity targetEntity,
  1388.       Property referencedProperty, String value) {
  1389.     // lookup record in audit data (for deleted records) to get its recordId
  1390.     OBCriteria<AuditTrailRaw> c = OBDal.getInstance().createCriteria(AuditTrailRaw.class);
  1391.     c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_ACTION, "D"));
  1392.     c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_TABLE, targetEntity.getTableId()));
  1393.     // c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_RECORDID, recordId));
  1394.     c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_COLUMN, referencedProperty.getColumnId()));
  1395.     c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_OLDCHAR, value));
  1396.     AuditTrailRaw atr = (AuditTrailRaw) c.uniqueResult();
  1397.     if (atr == null) {
  1398.       return "(unknown)";
  1399.     }
  1400.     // then use the record-id to do the identifier lookup
  1401.     return try2GetIdentifierViaPK(vars, targetEntity, atr.getRecordID());
  1402.   }
  1403.  
  1404.   private String try2GetIdentifierViaPK(VariablesSecureApp vars, Entity targetEntity,
  1405.       String recordId) {
  1406.     StringBuilder result = new StringBuilder();
  1407.  
  1408.     // loop over identifier columns and concatenate identifier value manually
  1409.     // if one of these identifiers cannot be retrieved use fall-back string for it
  1410.     for (Property prop : targetEntity.getIdentifierProperties()) {
  1411.       // get value for the property from audit data
  1412.       OBCriteria<AuditTrailRaw> c = OBDal.getInstance().createCriteria(AuditTrailRaw.class);
  1413.       c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_ACTION, "D"));
  1414.       c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_TABLE, targetEntity.getTableId()));
  1415.       c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_RECORDID, recordId));
  1416.       c.add(Restrictions.eq(AuditTrailRaw.PROPERTY_COLUMN, prop.getColumnId()));
  1417.       AuditTrailRaw atr = (AuditTrailRaw) c.uniqueResult();
  1418.       String value = "(unknown)";
  1419.       if (atr != null) {
  1420.         // get formatted old value
  1421.         value = getFormattedValue(vars, atr, false);
  1422.       }
  1423.       result.append(value);
  1424.       result.append(" - "); // delimiter between columns
  1425.     }
  1426.     // remove ' ' after last column
  1427.     result.setLength(result.length() - 3);
  1428.     return result.toString();
  1429.   }
  1430.  
  1431.   /**
  1432.    * The the translated (fall-back untranslated) name of a value of a specific list reference.
  1433.    *
  1434.    * @param listRef
  1435.    *          the list reference
  1436.    * @param value
  1437.    *          the value
  1438.    * @return translated name of the value in the listRef
  1439.    */
  1440.   private String getTranslatedListValueName(Reference listRef, String value) {
  1441.     OBCriteria<org.openbravo.model.ad.domain.List> critList = OBDal.getInstance().createCriteria(
  1442.         org.openbravo.model.ad.domain.List.class);
  1443.     critList.add(Restrictions.eq(org.openbravo.model.ad.domain.List.PROPERTY_REFERENCE, listRef));
  1444.     critList.add(Restrictions.eq(org.openbravo.model.ad.domain.List.PROPERTY_SEARCHKEY, value));
  1445.     org.openbravo.model.ad.domain.List list = (org.openbravo.model.ad.domain.List) critList
  1446.         .uniqueResult();
  1447.     if (list == null) {
  1448.       return value;
  1449.     }
  1450.     // check if we have a translation
  1451.     OBCriteria<ListTrl> critListTrl = OBDal.getInstance().createCriteria(ListTrl.class);
  1452.     critListTrl.add(Restrictions.eq(ListTrl.PROPERTY_LISTREFERENCE, list));
  1453.     critListTrl.add(Restrictions.eq(ListTrl.PROPERTY_LANGUAGE, OBContext.getOBContext()
  1454.         .getLanguage()));
  1455.     ListTrl trl = (ListTrl) critListTrl.uniqueResult();
  1456.     if (trl != null) {
  1457.       return trl.getName();
  1458.     } else {
  1459.       return list.getName();
  1460.     }
  1461.   }
  1462.  
  1463.   private String getExcludeAuditColumnNames(VariablesSecureApp vars, String tableId) {
  1464.     OBCriteria<Column> col = OBDal.getInstance().createCriteria(Column.class);
  1465.     col.add(Restrictions.eq("table.id", tableId));
  1466.     col.add(Restrictions.eq(Column.PROPERTY_EXCLUDEAUDIT, Boolean.TRUE));
  1467.     StringBuilder result = new StringBuilder();
  1468.     // loop over ExcludeAudit columns and concatenate column name
  1469.     List<Column> columnList = col.list();
  1470.     for (Column c : columnList) {
  1471.       result.append(c.getName());
  1472.       result.append(","); // delimiter between columns
  1473.     }
  1474.     // remove ',' after last column
  1475.     if (result.length() > 0) {
  1476.       result.setLength(result.length() - 1);
  1477.     }
  1478.     return result.toString();
  1479.   }
  1480.  
  1481.   /**
  1482.    * Helper function to parse a string with the specified date-format into a date object.
  1483.    *
  1484.    * @param inputDate
  1485.    *          string to parse
  1486.    * @param format
  1487.    *          dateFormat of the string
  1488.    * @return date object or null on parse error
  1489.    */
  1490.   private Date parseDate(String inputDate, SimpleDateFormat format) {
  1491.     if (inputDate != null && !inputDate.isEmpty()) {
  1492.       try {
  1493.         return format.parse(inputDate);
  1494.       } catch (ParseException pe) {
  1495.         log4j.error("Could not parse dateTo", pe);
  1496.       }
  1497.     }
  1498.     return null;
  1499.   }
  1500.  
  1501.   /**
  1502.    * Utility method which print the response to a DataGrid's STRUCTURE request.
  1503.    *
  1504.    * @param headers
  1505.    *          array describing the list of column shown in the grid
  1506.    */
  1507.   private void printGridStructureGeneric(SQLReturnObject[] headers, HttpServletResponse response,
  1508.       VariablesSecureApp vars) throws IOException, ServletException {
  1509.     XmlDocument xmlDocument = xmlEngine.readXmlTemplate(
  1510.         "org/openbravo/erpCommon/utility/DataGridStructure").createXmlDocument();
  1511.  
  1512.     String type = "Hidden";
  1513.     String title = "";
  1514.     String description = "";
  1515.  
  1516.     xmlDocument.setParameter("type", type);
  1517.     xmlDocument.setParameter("title", title);
  1518.     xmlDocument.setParameter("description", description);
  1519.     xmlDocument.setData("structure1", headers);
  1520.     response.setContentType("text/xml; charset=UTF-8");
  1521.     response.setHeader("Cache-Control", "no-cache");
  1522.     PrintWriter out = response.getWriter();
  1523.     out.println(xmlDocument.print());
  1524.     out.close();
  1525.   }
  1526.  
  1527. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement