Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House,
* Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
*
* This Original Work is licensed under the European Union Public Licence
* (EUPL) v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */

using FiftyOne.Pipeline.Engines.FiftyOne.FlowElements;
using FiftyOne.Pipeline.Engines.Services;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;

namespace FiftyOne.DeviceDetection.PropertyKeyed.FlowElements
{
/// <summary>
/// Builder for creating a <see cref="PropertyKeyedDeviceEngine"/>
/// configured for NativeModel lookups.
/// No validation is applied to NativeModel values.
/// </summary>
public class NativeModelEngineBuilder :
PropertyKeyedEngineBuilderBase<
NativeModelEngineBuilder,
PropertyKeyedDeviceEngine>
{
/// <summary>
/// Constructs a new instance of <see cref="NativeModelEngineBuilder"/>.
/// </summary>
/// <param name="loggerFactory">The factory used to create loggers.</param>
/// <param name="dataUpdateService">The data update service, if any.</param>
public NativeModelEngineBuilder(
ILoggerFactory loggerFactory,
IDataUpdateService dataUpdateService = null)
: base(loggerFactory, dataUpdateService)
{
SetProperty("NativeModel");
}

/// <inheritdoc/>
public override NativeModelEngineBuilder SetPerformanceProfile(
Pipeline.Engines.PerformanceProfiles profile)
{
_logger.LogWarning(Messages.PerformanceProfileNotSupported);
return this;
}

/// <inheritdoc/>
protected override PropertyKeyedDeviceEngine CreateEngine(
List<string> properties)
{
return new PropertyKeyedDeviceEngine(
_loggerFactory,
properties,
"NativeModel",
"native-profiles");
}

/// <summary>
/// Build the engine without a data file.
/// The engine resolves its data from DeviceDetectionHashEngine
/// via AddPipeline at runtime.
/// </summary>
/// <returns>The built engine.</returns>
public new PropertyKeyedDeviceEngine Build()
{
return BuildEngine();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,34 +93,6 @@ public PropertyKeyedDeviceEngineBuilder SetValidator(
return this;
}

/// <summary>
/// Configures the builder for TAC (Type Allocation Code) lookups.
/// Sets keyProperty to "TAC" and adds 8-digit validation.
/// </summary>
/// <returns>This builder.</returns>
public PropertyKeyedDeviceEngineBuilder ConfigureForTac()
{
_keyProperty = "TAC";
_elementDataKey = "tac-profiles";
_validator = ValidateTac;
SetProperty("TAC");
return this;
}

/// <summary>
/// Configures the builder for NativeModel lookups.
/// Sets keyProperty to "NativeModel" with no validation.
/// </summary>
/// <returns>This builder.</returns>
public PropertyKeyedDeviceEngineBuilder ConfigureForNativeModel()
{
_keyProperty = "NativeModel";
_elementDataKey = "native-profiles";
_validator = null;
SetProperty("NativeModel");
return this;
}

/// <inheritdoc/>
public override PropertyKeyedDeviceEngineBuilder SetPerformanceProfile(
Pipeline.Engines.PerformanceProfiles profile)
Expand Down Expand Up @@ -148,7 +120,8 @@ protected override PropertyKeyedDeviceEngine CreateEngine(
{
throw new PipelineConfigurationException(
"KeyProperty must be set before building. " +
"Call SetKeyProperty(), ConfigureForTac(), or ConfigureForNativeModel().");
"Call SetKeyProperty() or use a specialized builder " +
"such as TacEngineBuilder or NativeModelEngineBuilder.");
}

var elementDataKey = _elementDataKey ??
Expand All @@ -174,22 +147,5 @@ protected override PropertyKeyedDeviceEngine CreateEngine(
return BuildEngine();
}

/// <summary>
/// Validates TAC format: must be exactly 8 numeric digits.
/// </summary>
private static bool ValidateTac(string value, IFlowData data)
{
if (value.Length == 8 && int.TryParse(value, out _))
{
return true;
}

data.AddError(
new ArgumentException(string.Format(
Messages.IncorrectTacEvidence,
value)),
data.Pipeline.GetElement<PropertyKeyedDeviceEngine>());
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House,
* Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
*
* This Original Work is licensed under the European Union Public Licence
* (EUPL) v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */

using FiftyOne.Pipeline.Core.Data;
using FiftyOne.Pipeline.Engines.FiftyOne.FlowElements;
using FiftyOne.Pipeline.Engines.Services;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;

namespace FiftyOne.DeviceDetection.PropertyKeyed.FlowElements
{
/// <summary>
/// Builder for creating a <see cref="PropertyKeyedDeviceEngine"/>
/// configured for TAC (Type Allocation Code) lookups.
/// TAC values must be exactly 8 numeric digits.
/// </summary>
public class TacEngineBuilder :
PropertyKeyedEngineBuilderBase<
TacEngineBuilder,
PropertyKeyedDeviceEngine>
{
/// <summary>
/// Constructs a new instance of <see cref="TacEngineBuilder"/>.
/// </summary>
/// <param name="loggerFactory">The factory used to create loggers.</param>
/// <param name="dataUpdateService">The data update service, if any.</param>
public TacEngineBuilder(
ILoggerFactory loggerFactory,
IDataUpdateService dataUpdateService = null)
: base(loggerFactory, dataUpdateService)
{
SetProperty("TAC");
}

/// <inheritdoc/>
public override TacEngineBuilder SetPerformanceProfile(
Pipeline.Engines.PerformanceProfiles profile)
{
_logger.LogWarning(Messages.PerformanceProfileNotSupported);
return this;
}

/// <inheritdoc/>
protected override PropertyKeyedDeviceEngine CreateEngine(
List<string> properties)
{
return new PropertyKeyedDeviceEngine(
_loggerFactory,
properties,
"TAC",
"tac-profiles",
ValidateTac);
}

/// <summary>
/// Build the engine without a data file.
/// The engine resolves its data from DeviceDetectionHashEngine
/// via AddPipeline at runtime.
/// </summary>
/// <returns>The built engine.</returns>
public new PropertyKeyedDeviceEngine Build()
{
return BuildEngine();
}

/// <summary>
/// Validates TAC format: must be exactly 8 numeric digits.
/// </summary>
private static bool ValidateTac(string value, IFlowData data)
{
if (value.Length == 8 && int.TryParse(value, out _))
{
return true;
}

data.AddError(
new ArgumentException(string.Format(
Messages.IncorrectTacEvidence,
value)),
data.Pipeline.GetElement<PropertyKeyedDeviceEngine>());
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,31 +217,29 @@ public void Build_WithoutKeyProperty_Throws()
}

/// <summary>
/// ConfigureForTac should set appropriate defaults.
/// TacEngineBuilder should set appropriate defaults.
/// </summary>
[TestMethod]
public void ConfigureForTac_SetsDefaults()
public void TacEngineBuilder_SetsDefaults()
{
var builder = new PropertyKeyedDeviceEngineBuilder(
var engine = new TacEngineBuilder(
_loggerFactory,
new Mock<IDataUpdateService>().Object);

var engine = builder.ConfigureForTac().Build();
new Mock<IDataUpdateService>().Object)
.Build();

Assert.AreEqual("tac-profiles", engine.ElementDataKey);
}

/// <summary>
/// ConfigureForNativeModel should set appropriate defaults.
/// NativeModelEngineBuilder should set appropriate defaults.
/// </summary>
[TestMethod]
public void ConfigureForNativeModel_SetsDefaults()
public void NativeModelEngineBuilder_SetsDefaults()
{
var builder = new PropertyKeyedDeviceEngineBuilder(
var engine = new NativeModelEngineBuilder(
_loggerFactory,
new Mock<IDataUpdateService>().Object);

var engine = builder.ConfigureForNativeModel().Build();
new Mock<IDataUpdateService>().Object)
.Build();

Assert.AreEqual("native-profiles", engine.ElementDataKey);
}
Expand Down
Loading