IDEMPIERE-2771 Improve 2pack tracing for errors / implement mail notifier for 2packs

This commit is contained in:
Carlos Ruiz 2015-08-19 22:12:11 -05:00
parent 6d4e756e12
commit 4029fbd81c
12 changed files with 258 additions and 20 deletions

View File

@ -0,0 +1,11 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-2771 Improve 2pack tracing for errors
-- Aug 19, 2015 9:55:02 PM COT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200067,0,0,TO_DATE('2015-08-19 21:55:02','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2015-08-19 21:55:02','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','EMAIL_NOTIFY_2PACK',' ','EMail to get 2Pack Notifications','D','C','12ab33a5-4129-4d5b-9066-dbdbc20df816')
;
SELECT register_migration_script('201508192155_IDEMPIERE-2771.sql') FROM dual
;

View File

@ -0,0 +1,8 @@
-- IDEMPIERE-2771 Improve 2pack tracing for errors
-- Aug 19, 2015 9:55:02 PM COT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200067,0,0,TO_TIMESTAMP('2015-08-19 21:55:02','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2015-08-19 21:55:02','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','EMAIL_NOTIFY_2PACK',' ','EMail to get 2Pack Notifications','D','C','12ab33a5-4129-4d5b-9066-dbdbc20df816')
;
SELECT register_migration_script('201508192155_IDEMPIERE-2771.sql') FROM dual
;

View File

@ -42,7 +42,7 @@ public class MSysConfig extends X_AD_SysConfig
/**
*
*/
private static final long serialVersionUID = -2870394087507976203L;
private static final long serialVersionUID = 2300170888492939423L;
public static final String ADDRESS_VALIDATION = "ADDRESS_VALIDATION";
public static final String ALERT_SEND_ATTACHMENT_AS_XLS = "ALERT_SEND_ATTACHMENT_AS_XLS";
@ -79,6 +79,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String DOCACTIONBUTTON_SHOWACTIONNAME = "DOCACTIONBUTTON_SHOWACTIONNAME";
public static final String DPVIEWS_SHOWINFOACCOUNT = "DPViews_ShowInfoAccount";
public static final String DPVIEWS_SHOWINFOSCHEDULE = "DPViews_ShowInfoSchedule";
public static final String EMAIL_NOTIFY_2PACK = "EMAIL_NOTIFY_2PACK";
public static final String ENABLE_PAYMENTBOX_BUTTON = "ENABLE_PAYMENTBOX_BUTTON";
public static final String GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = "GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS";
public static final String HTML_REPORT_THEME = "HTML_REPORT_THEME";

View File

@ -48,6 +48,7 @@ import javax.mail.internet.MimeMultipart;
import org.compiere.model.MClient;
import org.compiere.model.MSysConfig;
import com.sun.mail.smtp.SMTPMessage;
/**
@ -72,7 +73,7 @@ public final class EMail implements Serializable
/**
*
*/
private static final long serialVersionUID = -5857825644737211294L;
private static final long serialVersionUID = 8117458371229316972L;
//use in server bean
public final static String HTML_MAIL_MARKER = "ContentType=text/html;";
@ -1200,4 +1201,12 @@ public final class EMail implements Serializable
email.send();
} // main
public void setHeader(String name, String value) {
try {
m_msg.setHeader(name, value);
} catch (MessagingException e) {
log.log(Level.WARNING, m_msg.toString(), e);
}
}
} // EMail

View File

@ -46,6 +46,7 @@ import org.compiere.model.MColumn;
import org.compiere.model.MRole;
import org.compiere.model.MTable;
import org.compiere.model.PO;
import org.compiere.model.X_AD_Package_Imp_Detail;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.xml.sax.SAXException;
@ -95,8 +96,13 @@ public class GenericPOElementHandler extends AbstractElementHandler {
element.unresolved = notfounds.toString();
return;
}
String action = po.is_new() ? "New" : "Update";
po.saveEx();
element.recordId = po.get_ID();
X_AD_Package_Imp_Detail impDetail = createImportDetail(ctx, element.qName, po.get_TableName(), po.get_Table_ID());
logImportDetail(ctx, impDetail, 1, po.toString(), element.recordId, action);
if ( I_AD_Window.Table_Name.equals(tableName)
|| I_AD_Process.Table_Name.equals(tableName)
|| I_AD_Role.Table_Name.equals(tableName)

View File

@ -51,6 +51,7 @@ public class SQLStatementElementHandler extends AbstractElementHandler {
Savepoint savepoint = null;
PreparedStatement pstmt = null;
X_AD_Package_Imp_Detail impDetail = null;
impDetail = createImportDetail(ctx, element.qName, "", 0);
try {
// NOTE Postgres needs to commit DDL statements
// add a SQL command just with COMMIT if you want to simulate the Oracle behavior (commit on DDL)
@ -86,6 +87,8 @@ public class SQLStatementElementHandler extends AbstractElementHandler {
stmt = null;
}
}
logImportDetail (ctx, impDetail, 1, "SQLStatement",1,"Execute");
ctx.packIn.getNotifier().addSuccessLine("-> " + sql);
} catch (Exception e) {
// rollback immediately on exception to avoid a wrong SQL stop the whole process
if (savepoint != null)
@ -101,6 +104,9 @@ public class SQLStatementElementHandler extends AbstractElementHandler {
}
savepoint = null;
}
ctx.packIn.getNotifier().addFailureLine("SQL statement failed but ignored, error (" + e.getLocalizedMessage() + "): " + sql);
logImportDetail (ctx, impDetail, 0, "SQLStatement",1,"Execute");
ctx.packIn.getNotifier().addFailureLine("-> " + sql);
log.log(Level.SEVERE,"SQLSatement", e);
} finally {
DB.close(pstmt);
@ -118,9 +124,6 @@ public class SQLStatementElementHandler extends AbstractElementHandler {
}
}
}
impDetail = createImportDetail(ctx, element.qName, "",
0);
logImportDetail (ctx, impDetail, 1, "SQLStatement",1,"Execute");
}
public void endElement(PIPOContext ctx, Element element) throws SAXException {

View File

@ -78,6 +78,8 @@ public class PipoDictionaryService implements IDictionaryService {
packIn.setPackageVersion(packageVersion);
packIn.setUpdateDictionary(false);
packIn.getNotifier().setFileName(packageFile.getName());
packIn.getNotifier().setPluginName(context.getBundle().getSymbolicName() + " v" + packageVersion);
adPackageImp = new X_AD_Package_Imp_Proc(Env.getCtx(), 0, null);
if (logger.isLoggable(Level.INFO)) logger.info("zipFilepath->" + packageFile);
@ -104,6 +106,7 @@ public class PipoDictionaryService implements IDictionaryService {
if (logger.isLoggable(Level.INFO)) logger.info("commit " + trxName);
} catch (Exception e) {
adPackageImp.setP_Msg(e.getLocalizedMessage());
packIn.getNotifier().addStatusLine(e.getLocalizedMessage());
logger.log(Level.SEVERE, "importXML:", e);
throw e;
} finally {
@ -122,6 +125,7 @@ public class PipoDictionaryService implements IDictionaryService {
attachment.save(); // ignoring exceptions
}
}
packIn.getNotifier().notifyRecipient();
}
}

View File

@ -100,6 +100,14 @@ public abstract class AbstractElementHandler implements ElementHandler {
detail.setSuccess(result);
detail.setRecord_ID(objectID);
ctx.packIn.addImportDetail(detail);
StringBuilder msg = new StringBuilder(action).append(" ");
if (detail.getTableName() != null)
msg.append(detail.getTableName());
msg.append("=").append(objectName).append("[").append(objectID).append("]");
if (success == 1)
ctx.packIn.getNotifier().addSuccessLine(msg.toString());
else
ctx.packIn.getNotifier().addFailureLine(msg.toString());
}
/**

View File

@ -61,6 +61,7 @@ public class PackIn {
private Map<String,Integer> columnCache = new HashMap<String,Integer>();
private String packageName = null;
private String packageVersion = null;
private PackInNotifier notifier = new PackInNotifier(this);
private X_AD_Package_Imp_Proc packinProc;
private List<X_AD_Package_Imp_Detail> importDetails;
@ -176,7 +177,9 @@ public class PackIn {
log.info(msg);
if (handler.getUnresolvedCount() > 0)
handler.dumpUnresolvedElements();
return "Processed="+handler.getElementsProcessed()+" Un-Resolved="+handler.getUnresolvedCount();
msg = "Processed="+handler.getElementsProcessed()+" Un-Resolved="+handler.getUnresolvedCount();
getNotifier().addStatusLine(msg);
return msg;
} catch (Exception e) {
log.log(Level.SEVERE, "importXML:", e);
throw new RuntimeException(e.getLocalizedMessage(), e);
@ -288,6 +291,10 @@ public class PackIn {
this.packageVersion = packageVersion;
}
public PackInNotifier getNotifier() {
return notifier;
}
public X_AD_Package_Imp_Proc getAD_Package_Imp_Proc() {
if (packinProc.getAD_Package_Imp_Proc_ID() == 0)
packinProc.saveEx(); // we need the ID to set

View File

@ -306,14 +306,13 @@ public class PackInHandler extends DefaultHandler {
updateRoleAccess();
if (!packageStatus.equals("Completed with errors")) {
if (getUnresolvedCount() > 0) {
packageStatus = "Completed - unresolved";
} else {
packageStatus = "Completed successfully";
packIn.setSuccess(true);
}
}
packIn.getNotifier().addStatusLine(packageStatus);
//Update package history log with package status
packageImp.setPK_Status(packageStatus);
@ -334,12 +333,14 @@ public class PackInHandler extends DefaultHandler {
processElement(e);
} catch (RuntimeException re) {
packageStatus = "Import Failed";
packIn.getNotifier().addStatusLine(packageStatus);
//Update package history log with package status
packageImp.setPK_Status(packageStatus);
packageImp.saveEx();
throw re;
} catch (SAXException se) {
packageStatus = "Import Failed";
packIn.getNotifier().addStatusLine(packageStatus);
//Update package history log with package status
packageImp.setPK_Status(packageStatus);
packageImp.saveEx();
@ -487,6 +488,7 @@ public class PackInHandler extends DefaultHandler {
if (e.unresolved != null && e.unresolved.length() > 0)
s.append(" unresolved ").append(e.unresolved);
log.warning(s.toString());
packIn.getNotifier().addFailureLine(s.toString());
}
}
}

View File

@ -0,0 +1,169 @@
/**********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Trek Global *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Developer: *
* - Carlos Ruiz - globalqss *
**********************************************************************/
package org.adempiere.pipo2;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.compiere.model.MClient;
import org.compiere.model.MSysConfig;
import org.compiere.util.EMail;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
/**
* PackIn Notifier
*
* @author Carlos Ruiz - globalqss - sponsored by Trek Global
*/
public class PackInNotifier {
private String fileName;
private String pluginName;
private List<KeyNamePair> knpLines = new ArrayList<KeyNamePair>();
private PackIn packIn;
public PackInNotifier(PackIn packIn) {
this.packIn = packIn;
}
private static final int LEVEL_STATUS = 0;
private static final int LEVEL_FAILURE = 1;
private static final int LEVEL_SUCCESS = 2;
public void addStatusLine(String msg) {
addLine(LEVEL_STATUS, msg);
}
public void addFailureLine(String msg) {
addLine(LEVEL_FAILURE, msg);
}
public void addSuccessLine(String msg) {
addLine(LEVEL_SUCCESS, msg);
}
public void addLine(int level, String msg) {
knpLines.add(new KeyNamePair(level, msg));
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getPluginName() {
return pluginName;
}
public void setPluginName(String pluginName) {
this.pluginName = pluginName;
}
public void notifyRecipient() {
// get list from current tenant
String emailList = MSysConfig.getValue(MSysConfig.EMAIL_NOTIFY_2PACK, "", Env.getAD_Client_ID(Env.getCtx())).trim();
String emailSys = MSysConfig.getValue(MSysConfig.EMAIL_NOTIFY_2PACK, "", 0).trim();
if (emailSys.length() > 0 && !emailList.equals(emailSys))
emailList += "," + emailSys;
if (emailList.length() == 0)
return;
// Compose Subject
StringBuilder subject = new StringBuilder("*");
String status;
if (packIn.isSuccess()) {
status = "Success";
} else {
status = "Failure";
}
subject.append(status).append("* Result for PackIn ").append(getFileName());
if (getPluginName() != null) {
subject.append(" from ").append(getPluginName());
}
// Body
StringBuilder message = new StringBuilder();
message.append("===========================\n");
message.append("Packin File: ").append(getFileName()).append("\n");
if (getPluginName() != null)
message.append("Plugin: ").append(getPluginName()).append("\n");
MClient client = MClient.get(Env.getCtx());
message.append("Executed on: ").append(client.getName()).append("\n");
message.append("Status: ").append(status).append("\n");
for (String line : getLines(LEVEL_STATUS)) {
message.append(line).append("\n");
}
message.append("===========================\n");
// --> if failed:
List<String> fLines = getLines(LEVEL_FAILURE);
if (fLines.size() > 0) {
message.append("Failed Objects:").append("\n");
for (String line : fLines) {
message.append(line).append("\n");
}
message.append("===========================\n");
}
List<String> sLines = getLines(LEVEL_SUCCESS);
if (sLines.size() > 0) {
message.append("Successful Objects:").append("\n");
for (String line : sLines) {
message.append(line).append("\n");
}
message.append("===========================\n");
}
StringTokenizer st = new StringTokenizer(emailList, " ,;", false);
String to = st.nextToken();
EMail email = client.createEMail(null, to, subject.toString(), message.toString());
if (email != null)
{
if (!packIn.isSuccess())
email.setHeader("X-Priority", "1");
while (st.hasMoreTokens())
email.addTo(st.nextToken());
status = email.send();
}
}
private List<String> getLines(int levelStatus) {
List<String> lines = new ArrayList<String>();
for (KeyNamePair knp : knpLines) {
if (knp.getKey() == levelStatus) {
lines.add(knp.getName());
}
}
return lines;
}
}

View File

@ -75,8 +75,7 @@ public class PackInProcess extends SvrProcess {
*/
protected String doIt() throws Exception {
X_AD_Package_Imp_Proc adPackageImp = new X_AD_Package_Imp_Proc(getCtx(),
p_PackIn_ID, get_TrxName());
X_AD_Package_Imp_Proc adPackageImp = new X_AD_Package_Imp_Proc(getCtx(), p_PackIn_ID, null); // out of trx
// Create Target directory if required
String packageDirectory = adPackageImp.getAD_Package_Dir();
@ -134,14 +133,25 @@ public class PackInProcess extends SvrProcess {
packIn.setPackageName(packageName);
packIn.setPackageVersion(packageVersion);
packIn.setUpdateDictionary(m_UpdateDictionary);
packIn.getNotifier().setFileName(zipFilepath.getName());
packIn.setAD_Package_Imp_Proc(adPackageImp);
// call XML Handler
String msg = packIn.importXML(dict_file, getCtx(), get_TrxName());
String msg;
try {
msg = packIn.importXML(dict_file, getCtx(), get_TrxName());
adPackageImp.setDateProcessed(new Timestamp(System.currentTimeMillis()));
adPackageImp.setP_Msg(msg);
adPackageImp.saveEx();
} catch (Exception e) {
adPackageImp.setP_Msg(e.getLocalizedMessage());
packIn.getNotifier().addStatusLine(e.getLocalizedMessage());
log.log(Level.SEVERE, "importXML:", e);
throw e;
} finally {
adPackageImp.save(); // ignoring exceptions
packIn.getNotifier().notifyRecipient();
}
return msg;
} // doIt
} // PackInProcess