Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port: Filter generic base types when seaching for the resource proxy type #512

Merged
merged 7 commits into from
Dec 20, 2024
8 changes: 4 additions & 4 deletions .build/Common.props
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project>

<PropertyGroup>
<AssemblyVersion>0.0.0</AssemblyVersion>
1nf0rmagician marked this conversation as resolved.
Show resolved Hide resolved
<AssemblyVersion>8.0.0</AssemblyVersion>
<AssemblyVersion Condition="'$(MORYX_ASSEMBLY_VERSION)'!=''">$(MORYX_ASSEMBLY_VERSION)</AssemblyVersion>

<FileVersion>0.0.0.0</FileVersion>
<FileVersion>8.0.0.0</FileVersion>
<FileVersion Condition="'$(MORYX_FILE_VERSION)'!=''">$(MORYX_FILE_VERSION)</FileVersion>

<InformationalVersion>0.0.0.0</InformationalVersion>
<InformationalVersion>8.0.0.0</InformationalVersion>
<InformationalVersion Condition="'$(MORYX_INFORMATIONAL_VERSION)'!=''">$(MORYX_INFORMATIONAL_VERSION)</InformationalVersion>

<PackageVersion>0.0.0</PackageVersion>
<PackageVersion>8.0.0</PackageVersion>
<PackageVersion Condition="'$(MORYX_PACKAGE_VERSION)'!=''">$(MORYX_PACKAGE_VERSION)</PackageVersion>

<Authors>PHOENIXCONTACT</Authors>
Expand Down
9 changes: 5 additions & 4 deletions MORYX-Framework.sln
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DFC092A6-B935-4D19-A564-9AEDEEF999B9}"
ProjectSection(SolutionItems) = preProject
Build.ps1 = Build.ps1
.build\Common.props = .build\Common.props
Directory.build.props = Directory.build.props
Directory.Build.targets = Directory.Build.targets
LICENSE = LICENSE
Expand Down Expand Up @@ -118,9 +119,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moryx.Runtime.Endpoints.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moryx.Runtime.Endpoints.IntegrationTests", "src\Tests\Moryx.Runtime.Endpoints.IntegrationTests\Moryx.Runtime.Endpoints.IntegrationTests.csproj", "{4FFB98A7-9A4C-476F-8BCC-C19B7F757BF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moryx.TestTools.NUnit", "src\Moryx.TestTools.NUnit\Moryx.TestTools.NUnit.csproj", "{6FF878E0-AF61-4C3A-9B9C-71C35A949E51}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moryx.TestTools.NUnit", "src\Moryx.TestTools.NUnit\Moryx.TestTools.NUnit.csproj", "{6FF878E0-AF61-4C3A-9B9C-71C35A949E51}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moryx.TestTools.IntegrationTest", "src\Moryx.TestTools.IntegrationTest\Moryx.TestTools.IntegrationTest.csproj", "{C949164C-0345-4893-9E4C-A79BC1F93F85}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moryx.TestTools.IntegrationTest", "src\Moryx.TestTools.IntegrationTest\Moryx.TestTools.IntegrationTest.csproj", "{C949164C-0345-4893-9E4C-A79BC1F93F85}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -356,8 +357,8 @@ Global
{C949164C-0345-4893-9E4C-A79BC1F93F85} = {953AAE25-26C8-4A28-AB08-61BAFE41B22F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
RESX_ShowErrorsInErrorList = True
RESX_TaskErrorCategory = Message
SolutionGuid = {36EFC961-F4E7-49DC-A36A-99594FFB8243}
RESX_TaskErrorCategory = Message
RESX_ShowErrorsInErrorList = True
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>REST Api in order to interact with the resource management</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;IIoT;IoT;Resource</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
31 changes: 31 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/Camera/ICameraDriver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Moryx.AbstractionLayer.Drivers;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how this makes it into this PR, that's already merged 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We found this to happen from time to time, Github just recognized changes from older merges that actually don't change anything🙈

using System.Threading.Tasks;

namespace Moryx.Drivers.Camera.Interfaces
{
/// <summary>
/// Interface for camera devices, that provide image data
/// </summary>
public interface ICameraDriver<TImage> : IDriver where TImage : class
{
/// <summary>
/// Registers an ICameraDriverListener that should be provided
/// with images.
/// </summary>
void Register(ICameraDriverListener<TImage> listener);

/// <summary>
/// Unregisters an ICameraDriverListener
/// </summary>
void Unregister(ICameraDriverListener<TImage> listener);

/// <summary>
/// Capture a single image from the camera
/// </summary>
/// <returns>
/// The image that was captured or null in case no image
/// could be retrieved
/// </returns>
Task<TImage?> CaptureImage();
}
}
18 changes: 18 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/Camera/ICameraDriverListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Moryx.AbstractionLayer.Drivers;
using System.Threading.Tasks;

namespace Moryx.Drivers.Camera.Interfaces
{
/// <summary>
/// Interface for objects that register as listeners to camera drivers
/// </summary>
public interface ICameraDriverListener<T> where T : class
{
/// <summary>
/// Invoked, when a new image is received by the camera
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
Task OnImage(T image);
}
}
1 change: 1 addition & 0 deletions src/Moryx.AbstractionLayer/Moryx.AbstractionLayer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Domain model types and definitions of Cyber-physical systems in IIoT projects.</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;IIoT;IoT;Hardware;Communication;Manufacturing;Industrial;Abstraction;Realtime</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Asp.Extensions/Moryx.Asp.Extensions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<Description>Extensions for the Integration of MORYX in ASP.NET Core</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;ASP</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Container/Moryx.Container.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>MORYX container functionality based on Castle.Windsor.</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Container;IoC</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Model.InMemory/Moryx.Model.InMemory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>InMemory extension for unit tests referencing Moryx.Model</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database;InMemory;Effort</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Model.PostgreSQL/Moryx.Model.PostgreSQL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Adapter for Moryx.Model on PostgreSQL</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database;Npgsql;PostgreSQL;Postgres</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Model.Sqlite/Moryx.Model.Sqlite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Adapter for Moryx.Model on Sqlite</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database;Sqlite</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Model/Moryx.Model.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Datamodel integration for MORYX applications based on Entity Framework</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Entity;Framework;EntityFramework;DataModel;Model;Database</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Notifications/Moryx.Notifications.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Types and interfaces for notifications within MORYX applications</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;IIoT;IoT;Notifications</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Moryx.Resources.Management
{
internal class ResourceManagementFacade : IResourceManagement, IFacadeControl
internal class ResourceManagementFacade : FacadeBase, IResourceManagement
{
#region Dependency Injection

Expand All @@ -22,19 +22,17 @@ internal class ResourceManagementFacade : IResourceManagement, IFacadeControl
#endregion

#region IFacadeControl
/// <see cref="IFacadeControl.ValidateHealthState"/>
public Action ValidateHealthState { get; set; }

/// <seealso cref="IFacadeControl"/>
public void Activate()
public override void Activate()
{
Manager.ResourceAdded += OnResourceAdded;
Manager.CapabilitiesChanged += OnCapabilitiesChanged;
Manager.ResourceRemoved += OnResourceRemoved;
}

/// <seealso cref="IFacadeControl"/>
public void Deactivate()
public override void Deactivate()
{
Manager.ResourceAdded -= OnResourceAdded;
Manager.CapabilitiesChanged -= OnCapabilitiesChanged;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<Description>ResourceManagement module composing and maintaining the resource graph as the habitat for digital twins of manufacturing assets.</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;IIoT;IoT;Manufacturing;API;Resource</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,17 +264,19 @@ private ResourceProxy InstantiateProxy(string typeName, Resource instance)
/// </summary>
private void ProvideProxyType(Type resourceType)
{
// Step 1: Find the least specific base type that offers the same amount of interfaces
// Step 1: Find the least specific base type that offers the same amount of interfaces and is not a generic itself
// ReSharper disable once AssignNullToNotNullAttribute -> FullName should be not null
var targetType = _typeCache[resourceType.ResourceType()];
var linker = targetType;

var interfaces = RelevantInterfaces(linker);
// Move up the type tree until the parent offers less interfaces than the current linker
while (linker.BaseType != null && interfaces.Count == RelevantInterfaces(linker.BaseType).Count)
// Move up the type tree until the parent offers less interfaces than the current linker, is abstract or a generic
while (linker.BaseType != null && !linker.BaseType.ResourceType.IsGenericType
&& interfaces.Count == RelevantInterfaces(linker.BaseType).Count)
{
linker = linker.BaseType;
}


// Step 2: Check if we already created a proxy for this type. If we already
// did use this one for the requested type as well.
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Kernel components that comprise the MORYX server side runtime environment</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Kernel;Runtime;Server</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx.Runtime/Moryx.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Description>Server side component types and implementations for MORYX applications</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Runtime;Server</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Moryx/Moryx.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<Description>Core package of the MORYX ecosystem. It defines the necessary types for MORYX compatibility as well as commonly required tools.</Description>
<CreatePackage>true</CreatePackage>
<PackageTags>MORYX;Serialization;Configuration;Logging;Core;Modules;Workplans</PackageTags>
<IsPackable>true</IsPackable>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,18 @@ public class ResourceWithGenericMethod : Resource, IGenericMethodCall, ISimpleRe
public event EventHandler SomeEvent;
public event EventHandler<ICapabilities> CapabilitiesChanged;

public IList<TChannel> GenericMethod<TChannel>(string identifier)
{
throw new NotImplementedException();
}

public int MultiplyFoo(int factor)
{
throw new NotImplementedException();
}

public int MultiplyFoo(int factor, ushort offset)
{
throw new NotImplementedException();
}

public void RaiseEvent()
{
throw new NotImplementedException();
}
public IList<TChannel> GenericMethod<TChannel>(string identifier) => throw new NotImplementedException();

public int MultiplyFoo(int factor) => throw new NotImplementedException();

public int MultiplyFoo(int factor, ushort offset) => throw new NotImplementedException();

public void RaiseEvent() => throw new NotImplementedException();
}

public interface IGenericBaseResourceInterface : IResource { }

public class GenericBaseResource<T> : Resource, IGenericBaseResourceInterface { }

public class InheritingFromGenericResource : GenericBaseResource<object> { }
}
14 changes: 14 additions & 0 deletions src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,20 @@ public void ProxyBuilderFiltersGenericInterfaces()
Assert.IsFalse(typeof(IGenericMethodCall).IsAssignableFrom(proxy.GetType()));
}

[Test]
public void ProxyBuilderSkipsGenericBaseTypes()
{
// Arrange
var driver = new InheritingFromGenericResource { Id = 42, Name = "A non generic resource inheriting from a generic base type" };

// Act
var proxy = _typeController.GetProxy(driver);

// Assert
Assert.IsNotNull(proxy);
Assert.IsFalse(typeof(GenericBaseResource<object>).IsAssignableFrom(proxy.GetType()));
}

[Test]
public void FacadeExceptionForGenericProxy()
{
Expand Down
Loading