diff --git a/certmgr/Core/ConsoleToolsException.cs b/certmgr/Core/ConsoleToolsException.cs new file mode 100644 index 0000000..a43ed96 --- /dev/null +++ b/certmgr/Core/ConsoleToolsException.cs @@ -0,0 +1,15 @@ +using CertMgr.Core.Utils; + +namespace CertMgr.Core; + +public class ConsoleToolsException : Exception +{ + internal ConsoleToolsException(string messageFormat, params object?[] messageArgs) + : base(StringFormatter.Format(messageFormat, messageArgs)) + { + } + internal ConsoleToolsException(Exception? innerException, string messageFormat, params object?[] messageArgs) + : base(StringFormatter.Format(messageFormat, messageArgs), innerException) + { + } +} diff --git a/certmgr/Core/JobExecutor.cs b/certmgr/Core/JobExecutor.cs index 6b0c214..4512452 100644 --- a/certmgr/Core/JobExecutor.cs +++ b/certmgr/Core/JobExecutor.cs @@ -77,11 +77,11 @@ internal sealed class JobExecutor } catch (Exception e) { - throw new CertMgrException(e, "Failed to instantiate job '{0}'", descriptor.JobType.Name); + throw new JobException(e, "Failed to instantiate job '{0}'", descriptor.JobType.Name); } if (job == null) { - throw new CertMgrException("Failed to instantiate job '{0}' (Possibly missing parameterless ctor?)", descriptor.JobType.Name); + throw new JobException("Failed to instantiate job '{0}' (Possibly missing parameterless ctor?)", descriptor.JobType.Name); } SettingsBuilder settingsBuilder = new SettingsBuilder(rawArgs, descriptor.SettingsType); @@ -103,7 +103,7 @@ internal sealed class JobExecutor sb.AppendFormat("\t- {0}: {1}", vr.ValueName, vr.Justification); sb.AppendLine(); } - throw new CertMgrException(sb.ToString()); + throw new JobException(sb.ToString()); } MethodInfo? settingsSetter = GetPropertyWithPrivateSetter(descriptor.JobType, "Settings"); @@ -113,7 +113,7 @@ internal sealed class JobExecutor } else { - throw new CertMgrException("Failed to initialize job '{0}'. Missing property 'Settings' (Possibly the job doesn't inherit from '{1}'?)", descriptor.JobType.Name, typeof(Job<>).Name); + throw new JobException("Failed to initialize job '{0}'. Missing property 'Settings' (Possibly the job doesn't inherit from '{1}'?)", descriptor.JobType.Name, typeof(Job<>).Name); } return job; diff --git a/certmgr/Core/Jobs/JobSettings.cs b/certmgr/Core/Jobs/JobSettings.cs index 2124810..4b55cc2 100644 --- a/certmgr/Core/Jobs/JobSettings.cs +++ b/certmgr/Core/Jobs/JobSettings.cs @@ -23,4 +23,9 @@ public abstract class JobSettings { return Task.CompletedTask; } + + public override string ToString() + { + return string.Format("type = '{0}'", GetType().ToString(false)); + } } diff --git a/certmgr/Core/PropertyDescriptor.cs b/certmgr/Core/PropertyDescriptor.cs index e1014d8..4cdf0a0 100644 --- a/certmgr/Core/PropertyDescriptor.cs +++ b/certmgr/Core/PropertyDescriptor.cs @@ -37,8 +37,6 @@ internal sealed class PropertyDescriptor public Utils.TypeInfo PropertyTypeInfo { [DebuggerStepThrough] get; } - public Type? ValidatorType => _settingAttribute.Validator; - public IValueValidator? CustomValidator { get @@ -52,7 +50,7 @@ internal sealed class PropertyDescriptor if (validator == null) { CLog.Error("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false)); - throw new CertMgrException("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false)); + throw new ConsoleToolsException("Failed to create instance of value-validator of type '{0}' for property '{1}' in class '{2}'", _settingAttribute.Validator.ToString(false), PropertyName, _settingsType.ToString(false)); } } @@ -73,6 +71,12 @@ internal sealed class PropertyDescriptor if (typeof(IValueConverter).IsAssignableFrom(valueConverter)) { converter = (IValueConverter?)Activator.CreateInstance(valueConverter); + + if (converter == null) + { + CLog.Error("Failed to create instance of value-conveter of type '{0}' for property '{1}' in class '{2}'", valueConverter.ToString(false), PropertyName, _settingsType.ToString(false)); + throw new ConsoleToolsException("Failed to create instance of value-converter of type '{0}' for property '{1}' in class '{2}'", valueConverter.ToString(false), PropertyName, _settingsType.ToString(false)); + } } else { @@ -111,36 +115,8 @@ internal sealed class PropertyDescriptor return succeeded; } - /// Returns types that validator handles. Usually there is just one type, but class can inherit from multiple ISettingValidator<T> types. - /// Type used to create instance of a type - /// List of types handled by validator. - private static IReadOnlyList GetValidatedTypes(Type validatorType) + public override string ToString() { - if (validatorType == null) - { - throw new ArgumentNullException(nameof(validatorType)); - } - - List validatedTypes = new List(); - - if (validatorType.IsInterface && validatorType.IsGenericType && validatorType.GetGenericTypeDefinition() == typeof(IValueValidator<>)) - { - Type candidate = validatorType.GetGenericArguments()[0]; - validatedTypes.Add(candidate); - } - - foreach (Type iface in validatorType.GetInterfaces()) - { - if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IValueValidator<>)) - { - Type candidate = iface.GetGenericArguments()[0]; - if (!validatedTypes.Contains(candidate)) - { - validatedTypes.Add(candidate); - } - } - } - - return validatedTypes; + return string.Format("property '{0}', type = {1}, is-mandatory = {2}, validator = {3}, converter = {4}", PropertyName, PropertyTypeInfo.SourceType.ToString(false), IsMandatory ? "yes" : "no", CustomValidator?.GetType().ToString(false) ?? "", CustomConverter?.GetType().ToString(false) ?? ""); } } diff --git a/certmgr/Core/SettingsBuilder.cs b/certmgr/Core/SettingsBuilder.cs index 36c5825..7a002e0 100644 --- a/certmgr/Core/SettingsBuilder.cs +++ b/certmgr/Core/SettingsBuilder.cs @@ -41,43 +41,12 @@ internal sealed class SettingsBuilder { IValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false); settings.ValidationResults.Add(valres); - - // IReadOnlyList validatedTypes = GetValidatedTypes(descriptor.ValidatorType); - // - // if (descriptor.PropertyTypeInfo.IsCollection) - // { - // Utils.TypeInfo validatedTypeInfo = TypeUtils.UnwrapCollection(validatedTypes[0]); - // if (validatedTypeInfo.IsCollection) - // { - // // validator validates collection => send whole collection as argument to ValidateAsync(..) - // ValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false); - // settings.ValidationResults.Add(valres); - // } - // else - // { - // // validator validates elements => send items one by one to ValidateAsync(..) - // if (setPropertyResult.Value is IList list) - // { - // foreach (object value in list) - // { - // ValidationResult valres = await validator.ValidateAsync(value, cancellationToken).ConfigureAwait(false); - // settings.ValidationResults.Add(valres); - // } - // } - // } - // } - // else - // { - // // setting is not a collection. lets assume the validator doesn't validate collection as well - // ValidationResult valres = await validator.ValidateAsync(setPropertyResult.Value, cancellationToken).ConfigureAwait(false); - // settings.ValidationResults.Add(valres); - // } } } catch (Exception e) { CLog.Error(e, "Failed to validate property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); - throw new CertMgrException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); + throw new ConsoleToolsException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); } } } @@ -85,36 +54,6 @@ internal sealed class SettingsBuilder return settings; } - private static IReadOnlyList GetValidatedTypes(Type validatorType) - { - if (validatorType == null) - { - throw new ArgumentNullException(nameof(validatorType)); - } - - List hits = new List(); - - if (validatorType.IsInterface && validatorType.IsGenericType && validatorType.GetGenericTypeDefinition() == typeof(IValueValidator<>)) - { - Type candidate = validatorType.GetGenericArguments()[0]; - hits.Add(candidate); - } - - foreach (Type iface in validatorType.GetInterfaces()) - { - if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IValueValidator<>)) - { - Type candidate = iface.GetGenericArguments()[0]; - if (!hits.Contains(candidate)) - { - hits.Add(candidate); - } - } - } - - return hits; - } - private async Task> SetPropertyValueAsync(JobSettings settings, PropertyDescriptor descriptor, CancellationToken cancellationToken) { object? convertedValue = null; @@ -135,7 +74,7 @@ internal sealed class SettingsBuilder catch (Exception e) { CLog.Error(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); - throw new CertMgrException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); + throw new ConsoleToolsException(e, "Failed to process property '{0}' (of type '{1}') in settings of type '{2}'", descriptor.PropertyName, descriptor.PropertyTypeInfo.SourceType.ToString(false), _settingsType.ToString(false)); } } else if (descriptor.IsMandatory) @@ -195,17 +134,17 @@ internal sealed class SettingsBuilder instance = Activator.CreateInstance(_settingsType); if (instance == null) { - throw new CertMgrException("Failed to create instance for settings of type '{0}'", _settingsType.Name); + throw new ConsoleToolsException("Failed to create instance for settings of type '{0}'", _settingsType.Name); } } catch (Exception e) { - throw new CertMgrException(e, "Failed to create instance for settings of type '{0}'", _settingsType.Name); + throw new ConsoleToolsException(e, "Failed to create instance for settings of type '{0}'", _settingsType.Name); } if (instance is not JobSettings settings) { - throw new CertMgrException("Failed to create instance for settings of type '{0}'. The type is not of type '{1}'", _settingsType.Name, typeof(JobSettings).Name); + throw new ConsoleToolsException("Failed to create instance for settings of type '{0}'. The type is not of type '{1}'", _settingsType.Name, typeof(JobSettings).Name); } return settings; @@ -268,59 +207,6 @@ internal sealed class SettingsBuilder return new AsyncResult(success, convertedValue); } - - /*private static object BuildCollectionValue(Type collectionType, Type elementType, IReadOnlyList items) - { - // convert source collection with 'items' of type 'object?' to collection with items of requested type: - Type listType = typeof(List<>).MakeGenericType(elementType); - IList typedList = (IList)Activator.CreateInstance(listType)!; - - foreach (object? item in items) - { - typedList.Add(item); - } - - if (collectionType.IsArray) - { - Array array = Array.CreateInstance(elementType, typedList.Count); - typedList.CopyTo(array, 0); - return array; - } - - // it is either IEnumerable or ICollection or IList or List - if (collectionType.IsAssignableFrom(listType)) - { - return typedList; - } - - // we do not know the type, but try to instantiate 'collectionType' and if it implements ICollection<>, then fill it - object? instance = Activator.CreateInstance(collectionType); - if (instance != null) - { - Type? iCollectionT = collectionType - .GetInterfaces() - .FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); - - if (iCollectionT != null) - { - MethodInfo? add = iCollectionT.GetMethod("Add"); - if (add != null) - { - foreach (object? item in typedList) - { - add.Invoke(instance, new object?[] { item }); - } - return instance; - } - } - } - - // try it as array, we fail anyway - Array fallback = Array.CreateInstance(elementType, typedList.Count); - typedList.CopyTo(fallback, 0); - return fallback; - }*/ - private bool TryConvertValue(string rawValue, Type targetType, out object? convertedValue) { convertedValue = null; diff --git a/certmgr/Core/Validation/ValidationException.cs b/certmgr/Core/Validation/ValidationException.cs new file mode 100644 index 0000000..d0cc4f6 --- /dev/null +++ b/certmgr/Core/Validation/ValidationException.cs @@ -0,0 +1,15 @@ +using CertMgr.Core.Utils; + +namespace CertMgr.Core.Validation; + +public sealed class ValidationException : Exception +{ + internal ValidationException(string messageFormat, params object?[] messageArgs) + : base(StringFormatter.Format(messageFormat, messageArgs)) + { + } + internal ValidationException(Exception? innerException, string messageFormat, params object?[] messageArgs) + : base(StringFormatter.Format(messageFormat, messageArgs), innerException) + { + } +} diff --git a/certmgr/Core/Validation/ValueValidatorT.cs b/certmgr/Core/Validation/ValueValidatorT.cs index 857b7e4..b64613e 100644 --- a/certmgr/Core/Validation/ValueValidatorT.cs +++ b/certmgr/Core/Validation/ValueValidatorT.cs @@ -24,9 +24,16 @@ public abstract class ValueValidator : IValueValidator } catch (Exception e) { - throw new CertMgrException(e, "'{0}': failed to convert value of type '{1}' to type '{2}' (value-name = '{3}')", GetType().ToString(false), value?.GetType().ToString(false) ?? "", typeof(T).ToString(false), ValueName); + throw new ValidationException(e, "'{0}': failed to convert value of type '{1}' to type '{2}' (value-name = '{3}')", GetType().ToString(false), value?.GetType().ToString(false) ?? "", typeof(T).ToString(false), ValueName); } - return ValidateAsync(typedValue, cancellationToken); + try + { + return ValidateAsync(typedValue, cancellationToken); + } + catch (Exception e) + { + throw new ValidationException(e, "'{0}': failed to validate value of type '{1}' (value-name = '{2}')", GetType().ToString(false), value?.GetType().ToString(false) ?? "", ValueName); + } } }