Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit 0ad35dd8 authored by Markus QUARITSCH's avatar Markus QUARITSCH
Browse files

refactoring: connect job directly to report viewmodels (without verifyresults...

refactoring: connect job directly to report viewmodels (without verifyresults as mediator), more validation tests,
parent dfe90e73
No related branches found
No related tags found
No related merge requests found
......@@ -17,7 +17,7 @@ using TUGraz.VectoHashing.Impl;
namespace HashingTool.ViewModel
{
public class HashComponentDataViewModel : HashedXMLFile, IMainView
public class HashComponentDataViewModel : VectoXMLFile, IMainView
{
private string _digestValue;
......@@ -30,7 +30,7 @@ namespace HashingTool.ViewModel
private bool _busy;
public HashComponentDataViewModel()
: base("Hash Component Data", HashingHelper.IsComponentFile)
: base("Hash Component Data", false, HashingHelper.IsComponentFile)
{
_xmlFile.PropertyChanged += SourceChanged;
_saveCommand = new RelayCommand(SaveDocument,
......
......@@ -15,7 +15,7 @@ namespace HashingTool.ViewModel.UserControl
{
private ViewModel.ComponentEntry[] _jobComponents;
private readonly ObservableCollection<string> _validationErrors = new ObservableCollection<string>();
private bool _manufacturerReportValid;
public ManufacturerReportXMLFile(string name, Func<XmlDocument, IErrorLogger, bool?> contentCheck,
Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, contentCheck, hashValidation)
......@@ -23,23 +23,11 @@ namespace HashingTool.ViewModel.UserControl
_xmlFile.PropertyChanged += UpdateComponents;
}
public ViewModel.ComponentEntry[] JobComponents
protected override void VerifyJobDataMatchesReport()
{
set {
if (_jobComponents == value) {
return;
}
_jobComponents = value;
DoUpdateComponents();
RaisePropertyChanged("JobComponents");
RaisePropertyChanged("ManufacturerReportValid");
}
private get { return _jobComponents; }
}
base.VerifyJobDataMatchesReport();
public ObservableCollection<string> ValidationErrors
{
get { return _validationErrors; }
DoUpdateComponentData();
}
private void UpdateComponents(object sender, PropertyChangedEventArgs e)
......@@ -47,22 +35,27 @@ namespace HashingTool.ViewModel.UserControl
if (e.PropertyName != "UPDATED") {
return;
}
DoUpdateComponents();
RaisePropertyChanged("ManufacturerReportValid");
DoUpdateComponentData();
RaisePropertyChanged("UPDATED");
}
private void DoUpdateComponents()
private void DoUpdateComponentData()
{
if (_xmlFile.Document == null || _xmlFile.Document.DocumentElement == null) {
if (_xmlFile.Document == null || _xmlFile.Document.DocumentElement == null ||
_xmlFile.IsValid != XmlFileStatus.ValidXML) {
Components = new ComponentEntry[] { };
VehicleIdentificationNumber = "";
RaisePropertyChanged("Components");
RaisePropertyChanged("VehicleIdentificationNumber");
return;
}
var components = GetContainigComponents().GroupBy(s => s)
.Select(g => new { Entry = g.Key, Count = g.Count() });
var jobComponents = _jobData == null ? new ViewModel.ComponentEntry[]{} : _jobData.Components.ToArray();
_validationErrors.Clear();
var hasComponentsFromJob = _jobData != null && _jobData.JobDataValid != null && _jobData.JobDataValid.Value && jobComponents.Any();
// iterate over components in manufacturer report, read out c14n, digest method, digest;
// collect c14n, digest method, digest value read, certification nr., digest value from job (re-computed)
var componentData = new List<ComponentEntry>();
foreach (var component in components) {
if (component.Entry == XMLNames.Component_Vehicle) {
......@@ -77,6 +70,7 @@ namespace HashingTool.ViewModel.UserControl
DigestValue = ReadElementValue(node, XMLNames.DI_Signature_Reference_DigestValue),
CertificationMethod = ReadElementValue(node, XMLNames.Report_Component_CertificationMethod),
};
// rename 'Axle' from report to 'Tyre' as in job
if (entry.Component.StartsWith("Axle ")) {
entry.Component = entry.Component.Replace("Axle", "Tyre");
entry.CertificationNumber = ReadElementValue(node, XMLNames.Report_Tyre_TyreCertificationNumber);
......@@ -85,81 +79,62 @@ namespace HashingTool.ViewModel.UserControl
entry.CertificationNumber = ReadElementValue(node, XMLNames.Report_Component_CertificationNumber) ??
ReadElementValue(node, XMLNames.Report_Component_CertificationMethod);
}
if (JobComponents != null) {
var jobComponent = JobComponents.Where(
x => x.Component == entry.Component).ToArray();
if (jobComponent.Any()) {
entry.DigestValueMatchesJobComponent = entry.Component.StartsWith("Tyre ")
? (bool?)null
: (jobComponent.First().DigestValueRead == entry.DigestValue);
entry.DigestValueExpected = jobComponent.First().DigestValueRead;
if (entry.CertificationMethod != CertificationMethod.StandardValues.ToXMLFormat()) {
entry.CertificationNumberMatchesJobComponent = jobComponent.First().CertificationNumber ==
entry.CertificationNumber;
entry.CertificationNumberExpected = jobComponent.First().CertificationNumber;
}
}
}
componentData.Add(entry);
if (!hasComponentsFromJob) {
continue;
}
var jobComponent = jobComponents.Where(x => x.Component == entry.Component).ToArray();
if (!jobComponent.Any()) {
continue;
}
entry.DigestValueMatchesJobComponent = entry.Component.StartsWith("Tyre ")
? (bool?)null
: (jobComponent.First().DigestValueComputed == entry.DigestValue);
entry.DigestValueExpected = jobComponent.First().DigestValueComputed;
if (entry.CertificationMethod == CertificationMethod.StandardValues.ToXMLFormat()) {
continue;
}
entry.CertificationNumberMatchesJobComponent = jobComponent.First().CertificationNumber ==
entry.CertificationNumber;
entry.CertificationNumberExpected = jobComponent.First().CertificationNumber;
}
}
Components = componentData.ToArray();
VehicleIdentificationNumber = GetVehicleIdentificationNumber();
RaisePropertyChanged("Components");
RaisePropertyChanged("VehicleIdentificationNumber");
}
private string GetVehicleIdentificationNumber()
{
if (_xmlFile.Document == null || _xmlFile.IsValid != XmlFileStatus.ValidXML || _xmlFile.ContentValid == null ||
!_xmlFile.ContentValid.Value) {
return "";
}
var node = _xmlFile.Document.SelectSingleNode(string.Format("//*[local-name()='{0}']", XMLNames.Vehicle_VIN));
if (node == null) {
return "";
var certificationNumberMismatch =
componentData.Where(
x => x.CertificationNumberMatchesJobComponent != null && !x.CertificationNumberMatchesJobComponent.Value).ToArray();
var digestMismatch =
componentData.Where(x => !x.Component.StartsWith("Tyre "))
.Where(x => x.DigestValueMatchesJobComponent == null || !x.DigestValueMatchesJobComponent.Value).ToArray();
if (jobComponents.Any()) {
foreach (var entry in certificationNumberMismatch) {
_validationErrors.Add(
string.Format(
"Verifying Manufacturer Report: Certification number for component '{0}' does not match! Job-file: '{1}', Report: '{2}'",
entry.Component, entry.CertificationNumberExpected, entry.CertificationNumber));
}
foreach (var entry in digestMismatch) {
_validationErrors.Add(
string.Format(
"Verifying Manufacturer Report: Digest Value for component '{0}' does not match! Job-file: '{1}', Report: '{2}'",
entry.Component, entry.DigestValueExpected, entry.DigestValue));
}
}
return node.InnerText;
ManufacturerReportValid = hasComponentsFromJob && !certificationNumberMismatch.Any() && !digestMismatch.Any();
}
public bool ManufacturerReportValid
{
get {
_validationErrors.Clear();
var componentsValid = JobComponents != null && JobComponents.Length > 0;
if (Components == null || JobComponents == null || JobComponents.Length == 0) {
return false;
}
foreach (var entry in Components) {
// certification number is optional (iff standard values are used)
var entryCertificationNbr = entry.CertificationNumberMatchesJobComponent == null ||
entry.CertificationNumberMatchesJobComponent.Value;
if (!entryCertificationNbr) {
var msg =
string.Format(
"Verifying Manufacturer Report: Certification number for component '{0}' does not match! Job-File: '{1}', Report: '{2}'",
entry.Component, entry.CertificationNumberExpected, entry.CertificationNumber);
_validationErrors.Add(msg);
}
componentsValid &= entryCertificationNbr;
// digest value is mandatory (except for tires)
if (entry.Component.StartsWith("Tyre ")) {
continue;
}
var entryDigest = entry.DigestValueMatchesJobComponent != null && entry.DigestValueMatchesJobComponent.Value;
if (!entryDigest) {
var msg =
string.Format(
"Verifying Manufacturer Report: Digest value for component '{0}' does not match! Job-File: '{1}', Report: '{2}'",
entry.Component, entry.DigestValueExpected, entry.DigestValue);
_validationErrors.Add(msg);
}
componentsValid &= entryDigest;
get { return _manufacturerReportValid; }
set {
if (_manufacturerReportValid == value) {
return;
}
return JobDigestValid && componentsValid;
_manufacturerReportValid = value;
RaisePropertyChanged("ManufacturerReportValid");
}
}
......@@ -217,7 +192,6 @@ namespace HashingTool.ViewModel.UserControl
return retVal;
}
public string VehicleIdentificationNumber { get; private set; }
public ComponentEntry[] Components { get; private set; }
......@@ -232,8 +206,11 @@ namespace HashingTool.ViewModel.UserControl
public string CertificationMethod { get; set; }
public bool? DigestValueMatchesJobComponent { get; set; }
public bool? CertificationNumberMatchesJobComponent { get; set; }
public string DigestValueExpected { get; set; }
public string CertificationNumberExpected { get; set; }
}
}
......
......@@ -3,32 +3,104 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Xml;
using TUGraz.VectoHashing;
namespace HashingTool.ViewModel.UserControl
{
public class ReportXMLFile : HashedXMLFile
{
protected readonly ObservableCollection<string> _validationErrors = new ObservableCollection<string>();
private string _jobDigestValueReadRead;
private string _jobDigestMethodRead;
private string[] _jobCanonicalizationMethodRead;
private string _jobDigestComputed;
private bool _jobDigestValid;
private bool _jobDigestMatchesReport;
protected VectoJobFile _jobData;
private string _reportVin;
public ReportXMLFile(string name, Func<XmlDocument, IErrorLogger, bool?> contentCheck,
Action<XmlDocument, VectoXMLFile> hashValidation = null)
: base(name, contentCheck, hashValidation)
{
_xmlFile.PropertyChanged += ReadJobDigest;
_xmlFile.PropertyChanged += ReportChanged;
}
public ObservableCollection<string> ValidationErrors
{
get { return _validationErrors; }
}
public VectoJobFile JobData
{
private get { return _jobData; }
set {
if (_jobData == value) {
return;
}
_jobData = value;
_jobData.PropertyChanged += JobDataChanged;
}
}
private void ReportChanged(object sender, PropertyChangedEventArgs e)
{
if (sender == _xmlFile && e.PropertyName == "UPDATED") {
ReadReportData();
VerifyJobDataMatchesReport();
}
}
private void ReadJobDigest(object sender, PropertyChangedEventArgs e)
protected virtual void JobDataChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "UPDATED") {
if (sender == _jobData && e.PropertyName == "UPDATED") {
VerifyJobDataMatchesReport();
}
}
// check digest value and vin of report against given job
protected virtual void VerifyJobDataMatchesReport()
{
if (_xmlFile.IsValid != XmlFileStatus.ValidXML || _jobData == null ||
_jobData.XMLFile.IsValid != XmlFileStatus.ValidXML) {
JobDigestValueComputed = "";
JobDigestMatchesReport = false;
return;
}
try {
var h = VectoHash.Load(_jobData.XMLFile.Document);
var jobDigest = h.ComputeHash(JobCanonicalizationMethodRead,
JobDigestMethodRead);
JobDigestValueComputed = jobDigest;
var digestMatch = _jobDigestComputed == JobDigestValueRead;
var vinMatch = _jobData.VehicleIdentificationNumber == ReportVIN;
if (!digestMatch) {
_validationErrors.Add(string.Format("Job Digest Value mismatch! Computed job digest: '{0}', digest read: '{1}'",
_jobDigestComputed, JobDigestValueRead));
}
if (!vinMatch) {
_validationErrors.Add(string.Format("VIN mismatch! VIN from job data: '{0}', VIN from report: '{1}'",
_jobData.VehicleIdentificationNumber, ReportVIN));
}
JobDigestMatchesReport = vinMatch
&& digestMatch;
} catch (Exception) {
JobDigestValueComputed = "";
JobDigestMatchesReport = false;
}
}
// readout all required fields from the report xml: c14n, digest method, digest value of job, VIN, ...
protected virtual void ReadReportData()
{
var jobDigest = "";
var jobDigestMethod = "";
var vin = "";
var jobc14NMethod = new string[] { };
if (_xmlFile.Document != null && _xmlFile.Document.DocumentElement != null) {
......@@ -49,13 +121,30 @@ namespace HashingTool.ViewModel.UserControl
if (c14NtMethodNodes != null) {
jobc14NMethod = (from XmlNode node in c14NtMethodNodes select node.InnerText).ToArray();
}
var vinNode = _xmlFile.Document.SelectSingleNode("//*[local-name()='VIN']");
if (vinNode != null) {
vin = vinNode.InnerText;
}
}
JobCanonicalizationMethodRead = jobc14NMethod;
JobDigestMethodRead = jobDigestMethod;
JobDigestValueRead = jobDigest;
ReportVIN = vin;
RaisePropertyChanged("UPDATED");
}
public string ReportVIN
{
get { return _reportVin; }
set {
if (_reportVin == value) {
return;
}
_reportVin = value;
RaisePropertyChanged("ReportVIN");
}
}
public string JobDigestMethodRead
{
get { return _jobDigestMethodRead; }
......@@ -95,26 +184,24 @@ namespace HashingTool.ViewModel.UserControl
public string JobDigestValueComputed
{
get { return _jobDigestComputed; }
set {
protected set {
if (_jobDigestComputed == value) {
JobDigestValid = _jobDigestComputed == JobDigestValueRead;
return;
}
_jobDigestComputed = value;
RaisePropertyChanged("JobDigestValueComputed");
JobDigestValid = _jobDigestComputed == JobDigestValueRead;
}
}
public bool JobDigestValid
public bool JobDigestMatchesReport
{
get { return _jobDigestValid; }
set {
if (_jobDigestValid == value) {
get { return _jobDigestMatchesReport; }
protected set {
if (_jobDigestMatchesReport == value) {
return;
}
_jobDigestValid = value;
RaisePropertyChanged("JobDigestValid");
_jobDigestMatchesReport = value;
RaisePropertyChanged("JobDigestMatchesReport");
}
}
}
......
......@@ -24,8 +24,10 @@ namespace HashingTool.ViewModel
_jobFile = new VectoJobFile("Job File", HashingHelper.IsJobFile, HashingHelper.HashJobFile);
_manufacturerReport = new ManufacturerReportXMLFile("Manufacturer Report", HashingHelper.IsManufacturerReport,
HashingHelper.ValidateDocumentHash);
_manufacturerReport.JobData = _jobFile;
_customerReport = new ReportXMLFile("Customer Report", HashingHelper.IsCustomerReport,
HashingHelper.ValidateDocumentHash);
_customerReport.JobData = _jobFile;
Files = new ObservableCollection<VectoXMLFile> { _jobFile, _manufacturerReport, _customerReport };
ErrorsAndWarnings = new CompositeCollection();
......@@ -34,11 +36,9 @@ namespace HashingTool.ViewModel
AddErrorCollection(_manufacturerReport.XMLFile.XMLValidationErrors);
AddErrorCollection(_customerReport.XMLFile.XMLValidationErrors);
AddErrorCollection(_manufacturerReport.ValidationErrors);
AddErrorCollection(_customerReport.ValidationErrors);
RaisePropertyChanged("CanonicalizationMethods");
_customerReport.PropertyChanged += Update;
_manufacturerReport.PropertyChanged += Update;
_jobFile.PropertyChanged += Update;
}
private void AddErrorCollection(ObservableCollection<string> errorCollection)
......@@ -57,17 +57,6 @@ namespace HashingTool.ViewModel
get { return ErrorsAndWarnings.Cast<CollectionContainer>().Sum(entry => (entry.Collection as ICollection).Count); }
}
private void Update(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "UPDATED") {
return;
}
UpdateReportJobDigest(_manufacturerReport);
UpdateReportJobDigest(_customerReport);
_manufacturerReport.JobComponents = _jobFile.Components.ToArray();
}
public string Name
{
......@@ -98,21 +87,5 @@ namespace HashingTool.ViewModel
public ObservableCollection<VectoXMLFile> Files { get; private set; }
public CompositeCollection ErrorsAndWarnings { get; private set; }
private void UpdateReportJobDigest(ReportXMLFile reportXML)
{
if (reportXML.FileIntegrityValid == null || !reportXML.FileIntegrityValid.Value || _jobFile.XMLFile.Document == null) {
reportXML.JobDigestValueComputed = "";
return;
}
try {
var h = VectoHash.Load(_jobFile.XMLFile.Document);
var jobDigest = h.ComputeHash(reportXML.JobCanonicalizationMethodRead,
reportXML.JobDigestMethodRead);
reportXML.JobDigestValueComputed = jobDigest;
} catch (Exception) {
reportXML.JobDigestValueComputed = "";
}
}
}
}
......@@ -48,7 +48,7 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,5">
<!--<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,5">
<Label>
<Label.Content>
<TextBlock Text="{Binding XMLFile.XMLValidationErrors.Count, StringFormat='{}{0} Warnings/Errors'}" />
......@@ -76,7 +76,7 @@
</Style>
</Button.Style>
</Button>
</StackPanel>
</StackPanel>-->
<Label Grid.Row="1" Grid.Column="0" Name="lblC14N" Content="Canonicalization:" HorizontalAlignment="Left"
Margin="0" />
......
......@@ -311,7 +311,7 @@
<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
<Style.Triggers>
<DataTrigger Binding="{Binding JobDigestValid}" Value="True">
<DataTrigger Binding="{Binding JobDigestMatchesReport}" Value="True">
<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
</DataTrigger>
</Style.Triggers>
......@@ -327,7 +327,7 @@
<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
<Style.Triggers>
<DataTrigger Binding="{Binding JobDigestValid}" Value="True">
<DataTrigger Binding="{Binding JobDigestMatchesReport}" Value="True">
<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
</DataTrigger>
</Style.Triggers>
......@@ -439,7 +439,7 @@
<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
<Style.Triggers>
<DataTrigger Binding="{Binding JobDigestValid}" Value="True">
<DataTrigger Binding="{Binding JobDigestMatchesReport}" Value="True">
<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
</DataTrigger>
</Style.Triggers>
......@@ -455,7 +455,7 @@
<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
<Style.Triggers>
<DataTrigger Binding="{Binding JobDigestValid}" Value="True">
<DataTrigger Binding="{Binding JobDigestMatchesReport}" Value="True">
<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
</DataTrigger>
</Style.Triggers>
......@@ -481,7 +481,7 @@
<Label Grid.Row="0" Grid.Column="0" Content="Vehicle" FontWeight="Bold" Margin="0,0,10,0" />
<Label Grid.Row="0" Grid.Column="1" Content="VIN:" />
<TextBox Grid.Row="0" Grid.Column="2" Text="{Binding VehicleIdentificationNumber, Mode=OneWay}"
<TextBox Grid.Row="0" Grid.Column="2" Text="{Binding ReportVIN, Mode=OneWay}"
Margin="10,2" IsReadOnly="True" />
<ItemsControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" DockPanel.Dock="Bottom"
......@@ -763,7 +763,7 @@
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" />
<Style.Triggers>
<DataTrigger Binding="{Binding CustomerReport.JobDigestValid}" Value="True">
<DataTrigger Binding="{Binding CustomerReport.JobDigestMatchesReport}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" />
</DataTrigger>
</Style.Triggers>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment