/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. 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., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
package org.compiere.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Level;
import javax.script.ScriptEngine;
import org.adempiere.base.Core;
import org.adempiere.base.event.EventManager;
import org.adempiere.base.event.EventProperty;
import org.adempiere.base.event.FactsEventData;
import org.adempiere.base.event.IEventManager;
import org.adempiere.base.event.IEventTopics;
import org.adempiere.base.event.ImportEventData;
import org.adempiere.base.event.LoginEventData;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.model.ImportValidator;
import org.adempiere.process.ImportProcess;
import org.compiere.acct.Fact;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Util;
import org.osgi.service.event.Event;
/**
* Model Validation Engine
*
* @author Jorg Janke
* @version $Id: ModelValidationEngine.java,v 1.2 2006/07/30 00:58:38 jjanke Exp $
*
* @author Teo Sarca, SC ARHIPAC SERVICE SRL
*
FR [ 1670025 ] ModelValidator.afterLoadPreferences will be useful
* BF [ 1679692 ] fireDocValidate doesn't treat exceptions as errors
* FR [ 1724662 ] Support Email should contain model validators info
* FR [ 2788276 ] Data Import Validator
* https://sourceforge.net/p/adempiere/feature-requests/712/
* BF [ 2804135 ] Global FactsValidator are not invoked
* https://sourceforge.net/p/adempiere/bugs/1936/
* BF [ 2819617 ] NPE if script validator rule returns null
* https://sourceforge.net/p/adempiere/bugs/1976/
* @author victor.perez@e-evolution.com, www.e-evolution.com
* BF [ 2947607 ] Model Validator Engine duplicate listeners
*/
public class ModelValidationEngine
{
/**
* Get Singleton instance
* @return singleton engine instance
*/
public synchronized static ModelValidationEngine get()
{
if (s_engine == null)
s_engine = new ModelValidationEngine();
return s_engine;
} // get
/** Engine Singleton */
private static ModelValidationEngine s_engine = null;
/** flag to indicate a missing model validation class */
private static String missingModelValidationMessage = "";
/**
* Private Constructor.
* Use {@link #get()} to get the singleton instance.
*/
private ModelValidationEngine ()
{
super ();
// Load global validators
MTable table = MTable.get(Env.getCtx(), X_AD_ModelValidator.Table_ID);
Query query = table.createQuery("IsActive='Y'", null);
query.setOrderBy("SeqNo");
try {
List entityTypes = query.list();
for (X_AD_ModelValidator entityType : entityTypes)
{
String className = entityType.getModelValidationClass();
if (className == null || className.length() == 0)
continue;
loadValidatorClass(null, className);
}
} catch (Exception e)
{
//logging to db will try to init ModelValidationEngine again!
e.printStackTrace();
missingModelValidationMessage = missingModelValidationMessage + e.toString() + " global" + '\n';
}
// Go through all Clients and start Validators
MClient[] clients = MClient.getAll(Env.getCtx());
for (int i = 0; i < clients.length; i++)
{
String classNames = clients[i].getModelValidationClasses();
if (classNames == null || classNames.length() == 0)
continue;
loadValidatorClasses(clients[i], classNames);
}
} // ModelValidatorEngine
/**
* Load validation instances
* @param client
* @param classNames Java class name list separated by semicolon
*/
private void loadValidatorClasses(MClient client, String classNames)
{
StringTokenizer st = new StringTokenizer(classNames, ";");
while (st.hasMoreTokens())
{
String className = null;
try
{
className = st.nextToken();
if (className == null)
continue;
className = className.trim();
if (className.length() == 0)
continue;
//
loadValidatorClass(client, className);
}
catch (Exception e)
{
//logging to db will try to init ModelValidationEngine again!
e.printStackTrace();
missingModelValidationMessage = missingModelValidationMessage + e.toString() + " on tenant " + client.getName() + '\n';
}
}
}
/**
* Load validator instance
* @param client
* @param className
*/
private void loadValidatorClass(MClient client, String className) {
try
{
//
ModelValidator validator = null;
validator = Core.getModelValidator(className);
if (validator == null)
{
missingModelValidationMessage = missingModelValidationMessage + " Missing class " + className +
(client != null ? (" on tenant " + client.getName()) : " global") + '\n';
}
else
{
initialize(validator, client);
}
}
catch (Exception e)
{
//logging to db will try to init ModelValidationEngine again!
e.printStackTrace();
missingModelValidationMessage = missingModelValidationMessage + e.toString() +
(client != null ? (" on tenant " + client.getName()) : " global") + '\n';
}
}
/** Logger */
private static CLogger log = CLogger.getCLogger(ModelValidationEngine.class);
/** Validators */
private ArrayList m_validators = new ArrayList();
/** Model Change Listeners */
private Hashtable> m_modelChangeListeners = new Hashtable>();
/** Document Validation Listeners */
private Hashtable> m_docValidateListeners = new Hashtable>();
/** Accounting Facts Validation Listeners */
private Hashtable>m_factsValidateListeners = new Hashtable>();
/** Data Import Validation Listeners */
private Hashtable>m_impValidateListeners = new Hashtable>();
private ArrayList m_globalValidators = new ArrayList();
/**
* Initialize and add validator to global or client validator list.
* @param validator
* @param client null for global validator, not null for client specific validator
*/
private void initialize(ModelValidator validator, MClient client)
{
if (client == null)
m_globalValidators.add(validator);
m_validators.add(validator);
validator.initialize(this, client);
} // initialize
/**
* Called when login is complete.
* - Call {@link ModelValidator#login(int, int, int)} on register validators.
* - Call script validator (AD_Table_ScriptValidator)
* - Fire {@link IEventTopics#AFTER_LOGIN} OSGi event.
* @param AD_Client_ID client
* @param AD_Org_ID org
* @param AD_Role_ID role
* @param AD_User_ID user
* @return error message or null
*/
public String loginComplete (int AD_Client_ID, int AD_Org_ID, int AD_Role_ID, int AD_User_ID)
{
for (int i = 0; i < m_validators.size(); i++)
{
ModelValidator validator = m_validators.get(i);
if (AD_Client_ID == validator.getAD_Client_ID()
|| m_globalValidators.contains(validator))
{
String error = validator.login(AD_Org_ID, AD_Role_ID, AD_User_ID);
if (error != null && error.length() > 0)
return error;
}
}
// now process the script model validator for login
List loginRules = MRule.getModelValidatorLoginRules (Env.getCtx());
if (loginRules != null) {
for (MRule loginRule : loginRules) {
// currently just JSR 223 supported
if ( loginRule.getRuleType().equals(MRule.RULETYPE_JSR223ScriptingAPIs)
&& loginRule.getEventType().equals(MRule.EVENTTYPE_ModelValidatorLoginEvent)) {
String error;
try {
ScriptEngine engine = loginRule.getScriptEngine();
if (engine == null) {
throw new AdempiereException("Engine not found: " + loginRule.getEngineName());
}
MRule.setContext(engine, Env.getCtx(), 0); // no window
// now add the method arguments to the engine
engine.put(MRule.ARGUMENTS_PREFIX + "Ctx", Env.getCtx());
engine.put(MRule.ARGUMENTS_PREFIX + "AD_Client_ID", AD_Client_ID);
engine.put(MRule.ARGUMENTS_PREFIX + "AD_Org_ID", AD_Org_ID);
engine.put(MRule.ARGUMENTS_PREFIX + "AD_Role_ID", AD_Role_ID);
engine.put(MRule.ARGUMENTS_PREFIX + "AD_User_ID", AD_User_ID);
Object retval = engine.eval(loginRule.getScript());
error = (retval == null ? "" : retval.toString());
} catch (Exception e) {
e.printStackTrace();
error = e.toString();
}
if (error != null && error.length() > 0)
return error;
}
}
}
//now process osgi event handler
LoginEventData eventData = new LoginEventData(AD_Client_ID, AD_Org_ID, AD_Role_ID, AD_User_ID);
Event event = EventManager.newEvent(IEventTopics.AFTER_LOGIN, eventData);
EventManager.getInstance().sendEvent(event);
@SuppressWarnings("unchecked")
List errors = (List) event.getProperty(IEventManager.EVENT_ERROR_MESSAGES);
if (errors != null && !errors.isEmpty()) {
Collections.reverse(errors);
StringBuilder eventErrors = new StringBuilder("");
for (String error : errors) {
eventErrors.append(error).append("
");
}
return eventErrors.toString();
}
if ((AD_User_ID == SystemIDs.USER_SYSTEM || AD_User_ID == SystemIDs.USER_SUPERUSER) && AD_Role_ID == SystemIDs.ROLE_SYSTEM)
; // don't validate for user system on role system
else
if (! Util.isEmpty(missingModelValidationMessage)) {
MSystem system = MSystem.get(Env.getCtx());
if (system.isFailOnMissingModelValidator())
return missingModelValidationMessage;
}
return null;
} // loginComplete
/**
* Add Model Change Listener for a table
* @param tableName table name
* @param listener listener (global or tenant specific)
*/
public void addModelChange (String tableName, ModelValidator listener)
{
if (tableName == null || listener == null)
return;
//
String propertyName =
m_globalValidators.contains(listener)
? tableName + "*"
: tableName + listener.getAD_Client_ID();
ArrayList list = m_modelChangeListeners.get(propertyName);
if (list == null)
{
list = new ArrayList();
list.add(listener);
m_modelChangeListeners.put(propertyName, list);
}
else
list.add(listener);
} // addModelValidator
/**
* Remove Model Change Listener for a table
* @param tableName table name
* @param listener listener (global or tenant specific)
*/
public void removeModelChange (String tableName, ModelValidator listener)
{
if (tableName == null || listener == null)
return;
String propertyName =
m_globalValidators.contains(listener)
? tableName + "*"
: tableName + listener.getAD_Client_ID();
ArrayList list = m_modelChangeListeners.get(propertyName);
if (list == null)
return;
list.remove(listener);
if (list.size() == 0)
m_modelChangeListeners.remove(propertyName);
} // removeModelValidator
/**
* Fire Model Change event of a table.
* - Call {@link ModelValidator#modelChange(PO, int)} on register validators.
* - Call script validator (AD_Table_ScriptValidator)
* - Fire IEventTopics.PO_* OSGi event.
* @param po PO instance for the event
* @param changeType ModelValidator.TYPE_*
* @return error message or NULL for no veto
*/
public String fireModelChange (PO po, int changeType)
{
if (po == null )
return null;
String propertyName = po.get_TableName() + "*";
ArrayList list = m_modelChangeListeners.get(propertyName);
if (list != null)
{
//ad_entitytype.modelvalidationclasses
String error = fireModelChange(po, changeType, list);
if (error != null && error.length() > 0)
return error;
}
propertyName = po.get_TableName() + po.getAD_Client_ID();
list = m_modelChangeListeners.get(propertyName);
if (list != null)
{
//ad_client.modelvalidationclasses
String error = fireModelChange(po, changeType, list);
if (error != null && error.length() > 0)
return error;
}
// now process the script model validator for this event
List scriptValidators =
MTableScriptValidator.getModelValidatorRules(
po.getCtx(),
po.get_Table_ID(),
ModelValidator.tableEventValidators[changeType]);
if (scriptValidators != null) {
for (MTableScriptValidator scriptValidator : scriptValidators) {
MRule rule = MRule.get(po.getCtx(), scriptValidator.getAD_Rule_ID());
// currently just JSR 223 supported
if ( rule != null
&& rule.isActive()
&& rule.getRuleType().equals(MRule.RULETYPE_JSR223ScriptingAPIs)
&& rule.getEventType().equals(MRule.EVENTTYPE_ModelValidatorTableEvent)) {
String error;
try {
ScriptEngine engine = rule.getScriptEngine();
if (engine == null) {
throw new AdempiereException("Engine not found: " + rule.getEngineName());
}
MRule.setContext(engine, po.getCtx(), 0); // no window
// now add the method arguments to the engine
engine.put(MRule.ARGUMENTS_PREFIX + "Ctx", po.getCtx());
engine.put(MRule.ARGUMENTS_PREFIX + "PO", po);
engine.put(MRule.ARGUMENTS_PREFIX + "Type", changeType);
engine.put(MRule.ARGUMENTS_PREFIX + "Event", ModelValidator.tableEventValidators[changeType]);
Object retval = engine.eval(rule.getScript());
error = (retval == null ? "" : retval.toString());
} catch (Exception e) {
e.printStackTrace();
error = e.toString();
}
if (error != null && error.length() > 0)
return error;
}
}
}
//now process osgi event handlers
Event event = EventManager.newEvent(ModelValidator.tableEventTopics[changeType],
new EventProperty(EventManager.EVENT_DATA, po), new EventProperty(EventManager.TABLE_NAME_PROPERTY, po.get_TableName()));
EventManager.getInstance().sendEvent(event);
@SuppressWarnings("unchecked")
List errors = (List) event.getProperty(IEventManager.EVENT_ERROR_MESSAGES);
if (errors != null && !errors.isEmpty()) {
Collections.reverse(errors);
StringBuilder eventErrors = new StringBuilder("");
for (String error : errors) {
eventErrors.append(error).append("
");
}
return eventErrors.toString();
}
return null;
} // fireModelChange
/**
* Fire model change event of a table.
* - Call {@link ModelValidator#modelChange(PO, int)} on register validators.
* @param po PO instance for the event
* @param changeType ModelValidator.TYPE_*
* @param list register validators
* @return error message or null
*/
private String fireModelChange(PO po, int changeType, ArrayList list)
{
for (int i = 0; i < list.size(); i++)
{
try
{
ModelValidator validator = list.get(i);
if (validator.getAD_Client_ID() == po.getAD_Client_ID()
|| m_globalValidators.contains(validator))
{
String error = validator.modelChange(po, changeType);
if (error != null && error.length() > 0)
{
if (log.isLoggable(Level.FINE))
{
log.log(Level.FINE, "po="+po+" validator="+validator+" changeType="+changeType);
}
return error;
}
}
}
catch (Exception e)
{
//log the exception
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
String error = e.getLocalizedMessage();
if (error == null)
error = e.toString();
return error;
}
}
return null;
}
/**
* Add Document Validation Listener for a table
* @param tableName table name
* @param listener listener (global or tenant specific)
*/
public void addDocValidate (String tableName, ModelValidator listener)
{
if (tableName == null || listener == null)
return;
//
String propertyName =
m_globalValidators.contains(listener)
? tableName + "*"
: tableName + listener.getAD_Client_ID();
ArrayList list = m_docValidateListeners.get(propertyName);
if (list == null)
{
list = new ArrayList();
list.add(listener);
m_docValidateListeners.put(propertyName, list);
}
else if (!list.contains(listener))
{
list.add(listener);
}
} // addDocValidate
/**
* Remove Document Validation Listener of a table
* @param tableName table name
* @param listener listener (global or tenant specific)
*/
public void removeDocValidate (String tableName, ModelValidator listener)
{
if (tableName == null || listener == null)
return;
String propertyName =
m_globalValidators.contains(listener)
? tableName + "*"
: tableName + listener.getAD_Client_ID();
ArrayList list = m_docValidateListeners.get(propertyName);
if (list == null)
return;
list.remove(listener);
if (list.size() == 0)
m_docValidateListeners.remove(propertyName);
} // removeDocValidate
/**
* Fire Document Validation event of a table.
* - Call {@link ModelValidator#docValidate(PO, int)} on register validators.
* - Call script validator (AD_Table_ScriptValidator)
* - Fire IEventTopics.DOC_* OSGi event.
* @param po PO instance for the event
* @param docTiming see ModelValidator.TIMING_ constants
* @return error message or null
*/
public String fireDocValidate (PO po, int docTiming)
{
if (po == null)
return null;
String propertyName = po.get_TableName() + "*";
ArrayList list = m_docValidateListeners.get(propertyName);
if (list != null)
{
//ad_entitytype.modelvalidationclasses
String error = fireDocValidate(po, docTiming, list);
if (error != null && error.length() > 0)
return error;
}
propertyName = po.get_TableName() + po.getAD_Client_ID();
list = m_docValidateListeners.get(propertyName);
if (list != null)
{
//ad_client.modelvalidationclasses
String error = fireDocValidate(po, docTiming, list);
if (error != null && error.length() > 0)
return error;
}
// now process the script model validator for this event
List scriptValidators =
MTableScriptValidator.getModelValidatorRules(
po.getCtx(),
po.get_Table_ID(),
ModelValidator.documentEventValidators[docTiming]);
if (scriptValidators != null) {
for (MTableScriptValidator scriptValidator : scriptValidators) {
MRule rule = MRule.get(po.getCtx(), scriptValidator.getAD_Rule_ID());
// currently just JSR 223 supported
if ( rule != null
&& rule.isActive()
&& rule.getRuleType().equals(MRule.RULETYPE_JSR223ScriptingAPIs)
&& rule.getEventType().equals(MRule.EVENTTYPE_ModelValidatorDocumentEvent)) {
String error;
try {
ScriptEngine engine = rule.getScriptEngine();
if (engine == null) {
throw new AdempiereException("Engine not found: " + rule.getEngineName());
}
MRule.setContext(engine, po.getCtx(), 0); // no window
// now add the method arguments to the engine
engine.put(MRule.ARGUMENTS_PREFIX + "Ctx", po.getCtx());
engine.put(MRule.ARGUMENTS_PREFIX + "PO", po);
engine.put(MRule.ARGUMENTS_PREFIX + "Type", docTiming);
engine.put(MRule.ARGUMENTS_PREFIX + "Event", ModelValidator.documentEventValidators[docTiming]);
Object retval = engine.eval(rule.getScript());
error = (retval == null ? "" : retval.toString());
} catch (Exception e) {
e.printStackTrace();
error = e.toString();
}
if (error != null && error.length() > 0)
return error;
}
}
}
//now process osgi event handlers
Event event = EventManager.newEvent(ModelValidator.documentEventTopics[docTiming],
new EventProperty(EventManager.EVENT_DATA, po), new EventProperty(EventManager.TABLE_NAME_PROPERTY, po.get_TableName()));
EventManager.getInstance().sendEvent(event);
@SuppressWarnings("unchecked")
List errors = (List) event.getProperty(IEventManager.EVENT_ERROR_MESSAGES);
if (errors != null && !errors.isEmpty()) {
Collections.reverse(errors);
StringBuilder eventErrors = new StringBuilder("");
for (String error : errors) {
eventErrors.append(error).append("
");
}
return eventErrors.toString();
}
return null;
} // fireDocValidate
/**
* Fire Document Validation event of a table.
* - Call {@link ModelValidator#docValidate(PO, int)} on register validators.
* @param po
* @param docTiming
* @param list register validators
* @return error message or null
*/
private String fireDocValidate(PO po, int docTiming, ArrayList list)
{
for (int i = 0; i < list.size(); i++)
{
ModelValidator validator = null;
try
{
validator = list.get(i);
if (validator.getAD_Client_ID() == po.getAD_Client_ID()
|| m_globalValidators.contains(validator))
{
String error = validator.docValidate(po, docTiming);
if (error != null && error.length() > 0)
{
if (log.isLoggable(Level.FINE))
{
log.log(Level.FINE, "po="+po+" validator="+validator+" timing="+docTiming);
}
return error;
}
}
}
catch (Exception e)
{
//log the stack trace
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Exceptions are errors and should stop the document processing - teo_sarca [ 1679692 ]
String error = e.getLocalizedMessage();
if (error == null)
error = e.toString();
return error;
}
}
return null;
}
/**
* Add Accounting Facts Validation Listener
* @param tableName table name
* @param listener listener (global or tenant specific)
*/
public void addFactsValidate (String tableName, FactsValidator listener)
{
if (tableName == null || listener == null)
return;
//
String propertyName =
(listener instanceof ModelValidator && m_globalValidators.contains((ModelValidator)listener))
? tableName + "*"
: tableName + listener.getAD_Client_ID();
ArrayList list = m_factsValidateListeners.get(propertyName);
if (list == null)
{
list = new ArrayList();
list.add(listener);
m_factsValidateListeners.put(propertyName, list);
}
else
list.add(listener);
} // addFactsValidate
/**
* Add Import Validation Listener of an import table
* @param importTableName table name
* @param listener listener
*/
public void addImportValidate (String importTableName, ImportValidator listener)
{
String propertyName = importTableName + "*";
ArrayList list = m_impValidateListeners.get(propertyName);
if (list == null)
{
list = new ArrayList();
list.add(listener);
m_impValidateListeners.put(propertyName, list);
}
else
{
list.add(listener);
}
}
/**
* Remove Accounting Facts Validation Listener of a table
* @param tableName table name
* @param listener listener
*/
public void removeFactsValidate (String tableName, FactsValidator listener)
{
if (tableName == null || listener == null)
return;
String propertyName =
(listener instanceof ModelValidator && m_globalValidators.contains((ModelValidator)listener))
? tableName + "*"
: tableName + listener.getAD_Client_ID();
ArrayList list = m_factsValidateListeners.get(propertyName);
if (list == null)
return;
list.remove(listener);
if (list.size() == 0)
m_factsValidateListeners.remove(propertyName);
} // removeFactsValidate
/**
* Fire Accounting Facts Validation event of a table.
* - Call {@link FactsValidator#factsValidate(MAcctSchema, List, PO)} on register validators.
* - Fire {@link IEventTopics#ACCT_FACTS_VALIDATE} OSGi event.
* @param schema
* @param facts
* @param po PO instance of event
* @return error message or null
*/
public String fireFactsValidate (MAcctSchema schema, List facts, PO po)
{
if (schema == null || facts == null || po == null)
return null;
String propertyName = po.get_TableName() + "*";
ArrayList list = m_factsValidateListeners.get(propertyName);
if (list != null)
{
//ad_entitytype.modelvalidationclasses
String error = fireFactsValidate(schema, facts, po, list);
if (error != null && error.length() > 0)
return error;
}
propertyName = po.get_TableName() + po.getAD_Client_ID();
list = m_factsValidateListeners.get(propertyName);
if (list != null)
{
//ad_client.modelvalidationclasses
String error = fireFactsValidate(schema, facts, po, list);
if (error != null && error.length() > 0)
return error;
}
//process osgi event handlers
FactsEventData eventData = new FactsEventData(schema, facts, po);
Event event = EventManager.newEvent(IEventTopics.ACCT_FACTS_VALIDATE,
new EventProperty(EventManager.EVENT_DATA, eventData), new EventProperty(EventManager.TABLE_NAME_PROPERTY, po.get_TableName()));
EventManager.getInstance().sendEvent(event);
@SuppressWarnings("unchecked")
List errors = (List) event.getProperty(IEventManager.EVENT_ERROR_MESSAGES);
if (errors != null && !errors.isEmpty()) {
Collections.reverse(errors);
StringBuilder eventErrors = new StringBuilder("");
for (String error : errors) {
eventErrors.append(error).append("
");
}
return eventErrors.toString();
}
return null;
} // fireFactsValidate
/**
* Fire Accounting Facts Validation event of a table.
* - Call {@link FactsValidator#factsValidate(MAcctSchema, List, PO)} on register validators.
* @param schema
* @param facts
* @param po PO instance of event
* @param list register validators
* @return error message or null
*/
private String fireFactsValidate(MAcctSchema schema, List facts, PO po, ArrayList list)
{
for (int i = 0; i < list.size(); i++)
{
FactsValidator validator = null;
try
{
validator = list.get(i);
if (validator.getAD_Client_ID() == po.getAD_Client_ID()
|| (validator instanceof ModelValidator && m_globalValidators.contains((ModelValidator)validator)))
{
String error = validator.factsValidate(schema, facts, po);
if (error != null && error.length() > 0)
{
if (log.isLoggable(Level.FINE))
{
log.log(Level.FINE, "po="+po+" schema="+schema+" validator="+validator);
}
return error;
}
}
}
catch (Exception e)
{
//log the stack trace
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Exceptions are errors and should stop the document processing - teo_sarca [ 1679692 ]
String error = e.getLocalizedMessage();
if (error == null)
error = e.toString();
return error;
}
}
return null;
}
/**
* Fire Import Validation event.
* - Call {@link ImportValidator#validate(ImportProcess, Object, Object, int)} on registered validators.
* - Fire IEventTopics.IMPORT_* OSGi event.
* @param process import process
* @param importModel import record (e.g. X_I_BPartner)
* @param targetModel target model (e.g. MBPartner, MBPartnerLocation, MUser)
* @param timing see ImportValidator.TIMING_* constants
*/
public void fireImportValidate (ImportProcess process, PO importModel, PO targetModel, int timing)
{
String propertyName = process.getImportTableName() + "*";
ArrayList list = m_impValidateListeners.get(propertyName);
if (list != null)
{
for (ImportValidator validator : list)
{
validator.validate(process, importModel, targetModel, timing);
}
}
//osgi event handler
ImportEventData eventData = new ImportEventData(process, importModel, targetModel);
String topic = null;
if (timing == ImportValidator.TIMING_AFTER_IMPORT)
topic = IEventTopics.IMPORT_AFTER_IMPORT;
else if (timing == ImportValidator.TIMING_AFTER_VALIDATE)
topic = IEventTopics.IMPORT_AFTER_VALIDATE;
else if (timing == ImportValidator.TIMING_BEFORE_IMPORT)
topic = IEventTopics.IMPORT_BEFORE_IMPORT;
else if (timing == ImportValidator.TIMING_BEFORE_VALIDATE)
topic = IEventTopics.IMPORT_BEFORE_VALIDATE;
Event event = EventManager.newEvent(topic, new EventProperty(EventManager.EVENT_DATA, eventData),
new EventProperty(EventManager.IMPORT_TABLE_NAME_PROPERTY, process.getImportTableName()));
EventManager.getInstance().sendEvent(event);
}
/**
* String Representation
* @return info
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("ModelValidationEngine[");
sb.append("Validators=#").append(m_validators.size())
.append(", ModelChange=#").append(m_modelChangeListeners.size())
.append(", DocValidate=#").append(m_docValidateListeners.size())
.append("]");
return sb.toString();
} // toString
/**
* Get Model Validation Engine Info
* @param sb optional string buffer
* @param ctx context
* @return Model Validation Engine Info
*
* author Teo Sarca, FR [ 1724662 ]
*/
public StringBuffer getInfoDetail(StringBuffer sb, Properties ctx) {
if (sb == null)
sb = new StringBuffer();
sb.append("=== ModelValidationEngine ===").append(Env.NL);
sb.append("Validators #").append(m_validators.size()).append(Env.NL);
for (ModelValidator mv : m_validators) {
sb.append(mv.toString()).append(Env.NL);
}
sb.append(Env.NL).append(Env.NL);
//
sb.append("ModelChange #").append(m_modelChangeListeners.size()).append(Env.NL);
Iterator it = m_modelChangeListeners.keySet().iterator();
while(it.hasNext()) {
String key = it.next();
ArrayList list = m_modelChangeListeners.get(key);
for (ModelValidator mv : list) {
sb.append(key).append(": ").append(mv.toString()).append(Env.NL);
}
}
sb.append(Env.NL).append(Env.NL);
//
sb.append("DocValidate #").append(m_docValidateListeners.size()).append(Env.NL);
it = m_docValidateListeners.keySet().iterator();
while(it.hasNext()) {
String key = it.next();
ArrayList list = m_docValidateListeners.get(key);
for (ModelValidator mv : list) {
sb.append(key).append(": ").append(mv.toString()).append(Env.NL);
}
}
sb.append(Env.NL).append(Env.NL);
//
return sb;
}
/**
* After Load Preferences into Context for selected client.
* Fire afterLoadPreferences model validator event and {@link IEventTopics#PREF_AFTER_LOAD} OSGi event.
* @param ctx context
* @see org.compiere.util.Login#loadPreferences(KeyNamePair, KeyNamePair, java.sql.Timestamp, String)
* author Teo Sarca - FR [ 1670025 ] - https://sourceforge.net/p/adempiere/feature-requests/78/
*/
public void afterLoadPreferences (Properties ctx)
{
int AD_Client_ID = Env.getAD_Client_ID(ctx);
for (int i = 0; i < m_validators.size(); i++)
{
ModelValidator validator = m_validators.get(i);
if (AD_Client_ID == validator.getAD_Client_ID()
|| m_globalValidators.contains(validator))
{
java.lang.reflect.Method m = null;
try {
m = validator.getClass().getMethod("afterLoadPreferences", new Class[]{Properties.class});
}
catch(NoSuchMethodException e) {
// ignore
}
try {
if (m != null)
m.invoke(validator, ctx);
}
catch (Exception e) {
log.warning("" + validator + ": " + e.getLocalizedMessage());
}
}
}
//osgi event handlers
Event event = new Event(IEventTopics.PREF_AFTER_LOAD, (Map)null);
EventManager.getInstance().sendEvent(event);
}
/**
* Before Save Properties for selected client.
* @deprecated for deprecated swing client only
*/
@Deprecated
public void beforeSaveProperties ()
{
int AD_Client_ID = Env.getAD_Client_ID(Env.getCtx());
for (int i = 0; i < m_validators.size(); i++)
{
ModelValidator validator = m_validators.get(i);
if (AD_Client_ID == validator.getAD_Client_ID()
|| m_globalValidators.contains(validator))
{
java.lang.reflect.Method m = null;
try {
m = validator.getClass().getMethod("beforeSaveProperties");
}
catch(NoSuchMethodException e) {
// ignore
}
try {
if (m != null)
m.invoke(validator);
}
catch (Exception e) {
log.warning("" + validator + ": " + e.getLocalizedMessage());
}
}
}
}
} // ModelValidatorEngine