242 lines
10 KiB
C#
242 lines
10 KiB
C#
//
|
|
// Class: RuleEngine
|
|
// Current CLR: 4.0.30319.34209
|
|
// System: Microsoft Visual Studio 10.0
|
|
// Author: dani
|
|
// Created: 9/7/2015 8:16:42 AM
|
|
//
|
|
// Copyright (c) 2015 Informatikbüro Daniel Schick. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text.RegularExpressions;
|
|
using log4net;
|
|
|
|
namespace bsmd.database
|
|
{
|
|
public class RuleEngine
|
|
{
|
|
private static ILog log = LogManager.GetLogger(typeof(RuleEngine));
|
|
private static Dictionary<int, string> errorTextList = null;
|
|
private static Dictionary<int, string> violationTextList = null;
|
|
|
|
private Dictionary<DatabaseEntity, List<MessageError>> errorDict = new Dictionary<DatabaseEntity, List<MessageError>>();
|
|
private Dictionary<DatabaseEntity, List<MessageViolation>> violationDict = new Dictionary<DatabaseEntity, List<MessageViolation>>();
|
|
|
|
public RuleEngine()
|
|
{
|
|
if (RuleEngine.errorTextList == null)
|
|
RuleEngine.errorTextList = DBManager.Instance.LoadErrorTexts();
|
|
if (RuleEngine.violationTextList == null)
|
|
RuleEngine.violationTextList = DBManager.Instance.LoadViolationTexts();
|
|
}
|
|
|
|
public Dictionary<DatabaseEntity, List<MessageError>> ErrorDict { get { return this.errorDict; } }
|
|
public Dictionary<DatabaseEntity, List<MessageViolation>> ViolationDict { get { return this.violationDict; } }
|
|
|
|
#region public static property validation
|
|
|
|
/// <summary>
|
|
/// Test function checks decorated properties on an entity for errors (only errors, violations cannot
|
|
/// happen here)
|
|
/// </summary>
|
|
/// <param name="entity"></param>
|
|
/// <param name="errors"></param>
|
|
public static void ValidateProperties(DatabaseEntity entity, List<MessageError> errors)
|
|
{
|
|
|
|
Type objType = entity.GetType();
|
|
|
|
Type attribType = typeof(Validation1Attribute);
|
|
if (entity.GetValidationBlock() == DatabaseEntity.ValidationBlock.BLOCK2)
|
|
attribType = typeof(Validation2Attribute);
|
|
|
|
List<PropertyInfo> props = new List<PropertyInfo>();
|
|
|
|
// add "generic" validation properties to check list
|
|
props.AddRange(objType.GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(ValidationAttribute))));
|
|
// add "block" validation properties to check list
|
|
props.AddRange(objType.GetProperties().Where( prop => Attribute.IsDefined(prop, attribType)) );
|
|
|
|
foreach (PropertyInfo property in props)
|
|
{
|
|
object propValue = property.GetValue(entity, null);
|
|
string value = (propValue == null) ? string.Empty : propValue.ToString();
|
|
ValidationCode validationCode = ValidationCode.NONE;
|
|
if (Attribute.IsDefined(property, attribType))
|
|
{
|
|
if (entity.GetValidationBlock() == DatabaseEntity.ValidationBlock.BLOCK1)
|
|
{
|
|
Validation1Attribute validationAttribute = Attribute.GetCustomAttribute(property, typeof(Validation1Attribute))
|
|
as Validation1Attribute;
|
|
validationCode = validationAttribute.Code;
|
|
}
|
|
else
|
|
{
|
|
Validation2Attribute validationAttribute = Attribute.GetCustomAttribute(property, typeof(Validation2Attribute))
|
|
as Validation2Attribute;
|
|
validationCode = validationAttribute.Code;
|
|
}
|
|
}
|
|
if (validationCode == ValidationCode.NONE)
|
|
{
|
|
if (Attribute.IsDefined(property, typeof(ValidationAttribute)))
|
|
{
|
|
ValidationAttribute validationAttribute = Attribute.GetCustomAttribute(property, typeof(ValidationAttribute))
|
|
as ValidationAttribute;
|
|
validationCode = validationAttribute.Code;
|
|
}
|
|
}
|
|
|
|
// check properties
|
|
|
|
switch (validationCode)
|
|
{
|
|
case ValidationCode.NOT_NULL:
|
|
if (value.Length == 0) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
break;
|
|
case ValidationCode.LOCODE:
|
|
{
|
|
Regex rgx = new Regex("[A-Z]{2}[A-Z0-9]{3}");
|
|
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
case ValidationCode.LOCODE_GER:
|
|
{
|
|
// TODO: Jan nach der Liste anhauen
|
|
Regex rgx = new Regex("[A-Z]{2}[A-Z0-9]{3}");
|
|
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
case ValidationCode.INT_GT_ZERO:
|
|
{
|
|
int intVal = 0;
|
|
if (!Int32.TryParse(value, out intVal) || intVal <= 0)
|
|
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
case ValidationCode.DOUBLE_GT_ZERO:
|
|
{
|
|
double dVal = 0;
|
|
if (!Double.TryParse(value, out dVal) || dVal <= 0)
|
|
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
case ValidationCode.GISIS:
|
|
{
|
|
Regex rgx = new Regex("[0-9]{4}");
|
|
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
case ValidationCode.FLAG_CODE:
|
|
{
|
|
Regex rgx = new Regex("[A-Z]{2}");
|
|
if(!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
case ValidationCode.TWO_DIGIT:
|
|
{
|
|
Regex rgx = new Regex("[0-9]{2}");
|
|
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public methods
|
|
|
|
/// <summary>
|
|
/// Diese Funktion wird für Nachrichtenklassen (MDH, SEC,.. usw.) aufgerufen. Error in eingebetteten
|
|
/// Klassen werden dann der Nachrichtenklasse zugeordnet (können dann logischerweise mehrfach auftreten)
|
|
/// </summary>
|
|
public void Validate(DatabaseEntity entity)
|
|
{
|
|
if (!(entity is Message)) return;
|
|
|
|
List<MessageError> errors = new List<MessageError>();
|
|
List<MessageViolation> violations = new List<MessageViolation>();
|
|
this.errorDict[entity] = errors;
|
|
this.violationDict[entity] = violations;
|
|
|
|
foreach (DatabaseEntity derivedEntity in ((Message)entity).Elements)
|
|
{
|
|
// individuelle Fehler nach Nachrichtenklasse prüfen
|
|
derivedEntity.MessageCore = entity.MessageCore; // some instance we need info from core (NOA / Transit)
|
|
RuleEngine.ValidateProperties(derivedEntity, errors);
|
|
derivedEntity.Validate(errors, violations);
|
|
|
|
}
|
|
|
|
foreach (MessageError error in errors)
|
|
{
|
|
error.MessageHeaderId = entity.Id.Value;
|
|
DBManager.Instance.Save(error);
|
|
}
|
|
|
|
foreach (MessageViolation violation in violations)
|
|
{
|
|
violation.MessageHeaderId = entity.Id.Value;
|
|
DBManager.Instance.Save(violation);
|
|
}
|
|
|
|
log.InfoFormat("Msg Id {0} Type {1} has {2} errors and {3} violations",
|
|
entity.Id, entity.MessageNotificationClass, errors.Count, violations.Count);
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region private helper
|
|
|
|
internal static MessageError CreateError(ValidationCode validationCode, string p, string value)
|
|
{
|
|
|
|
MessageError error = new MessageError();
|
|
|
|
error.ErrorCode = (int)validationCode;
|
|
if (errorTextList.ContainsKey((int)validationCode))
|
|
{
|
|
error.ErrorText = string.Format(errorTextList[(int)validationCode], p, value);
|
|
}
|
|
else
|
|
{
|
|
error.ErrorText = p;
|
|
if (value != null)
|
|
error.ErrorText += " - " + value;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
internal static MessageViolation CreateViolation(ValidationCode validationCode, string p, string value)
|
|
{
|
|
|
|
MessageViolation violation = new MessageViolation();
|
|
|
|
violation.ViolationCode = (int)validationCode;
|
|
if (violationTextList.ContainsKey((int)validationCode))
|
|
{
|
|
violation.ViolationText = string.Format(violationTextList[(int)validationCode], p, value);
|
|
}
|
|
else
|
|
{
|
|
violation.ViolationText = p;
|
|
if (value != null)
|
|
violation.ViolationText += " - " + value;
|
|
}
|
|
return violation;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|