Skip to content

Commit 74cfe24

Browse files
Copilotdandrejvv
andcommitted
Phase 1-3 complete: Shared project, API and Factory extensions implemented
Co-authored-by: dandrejvv <[email protected]>
1 parent 9573ea3 commit 74cfe24

File tree

8 files changed

+323
-1
lines changed

8 files changed

+323
-1
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using Intent.Metadata.Models;
3+
using Intent.Modelers.Eventing.Api;
4+
using Intent.Modules.Common;
5+
using Intent.RoslynWeaver.Attributes;
6+
7+
[assembly: DefaultIntentManaged(Mode.Fully)]
8+
[assembly: IntentTemplate("Intent.ModuleBuilder.Templates.Api.ApiElementModelExtensions", Version = "1.0")]
9+
10+
namespace Intent.Aws.Sqs.Api
11+
{
12+
public static class MessageModelStereotypeExtensions
13+
{
14+
public static AwsSqs GetAwsSqs(this MessageModel model)
15+
{
16+
var stereotype = model.GetStereotype(AwsSqs.DefinitionId);
17+
return stereotype != null ? new AwsSqs(stereotype) : null;
18+
}
19+
20+
public static bool HasAwsSqs(this MessageModel model)
21+
{
22+
return model.HasStereotype(AwsSqs.DefinitionId);
23+
}
24+
25+
public static bool TryGetAwsSqs(this MessageModel model, out AwsSqs stereotype)
26+
{
27+
if (!HasAwsSqs(model))
28+
{
29+
stereotype = null;
30+
return false;
31+
}
32+
33+
stereotype = new AwsSqs(model.GetStereotype(AwsSqs.DefinitionId));
34+
return true;
35+
}
36+
37+
public class AwsSqs
38+
{
39+
private IStereotype _stereotype;
40+
public const string DefinitionId = "f0b7e50e-71a9-4f31-9f9a-3c3e0b5d8f2e";
41+
42+
public AwsSqs(IStereotype stereotype)
43+
{
44+
_stereotype = stereotype;
45+
}
46+
47+
public string Name => _stereotype.Name;
48+
49+
public string QueueName()
50+
{
51+
return _stereotype.GetProperty<string>("Queue Name");
52+
}
53+
54+
public string QueueUrl()
55+
{
56+
return _stereotype.GetProperty<string>("Queue URL");
57+
}
58+
}
59+
}
60+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Intent.Engine;
2+
using Intent.Modules.Common;
3+
using Intent.Modules.Common.Plugins;
4+
using Intent.Modules.Integration.IaC.Shared.AwsSqs;
5+
using Intent.Plugins.FactoryExtensions;
6+
using Intent.RoslynWeaver.Attributes;
7+
8+
[assembly: DefaultIntentManaged(Mode.Fully)]
9+
[assembly: IntentTemplate("Intent.ModuleBuilder.Templates.FactoryExtension", Version = "1.0")]
10+
11+
namespace Intent.Modules.Aws.Sqs.FactoryExtensions
12+
{
13+
[IntentManaged(Mode.Fully, Body = Mode.Merge)]
14+
public class MetadataLoaderExtension : FactoryExtensionBase
15+
{
16+
public override string Id => "Intent.Aws.Sqs.MetadataLoaderExtension";
17+
18+
[IntentManaged(Mode.Ignore)]
19+
public override int Order => 0;
20+
21+
protected override void OnAfterMetadataLoad(IApplication application)
22+
{
23+
IntegrationManager.Initialize(application);
24+
}
25+
}
26+
}

Modules/Intent.Modules.Aws.Sqs/Intent.Modules.Aws.Sqs.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@
2020
<PackageReference Include="Intent.SoftwareFactory.SDK" Version="3.10.0-pre.2" />
2121
</ItemGroup>
2222

23+
<Import Project="..\Intent.Modules.Integration.IaC.Shared.AwsSqs\Intent.Modules.Integration.IaC.Shared.AwsSqs.projitems" Label="Shared" />
24+
2325
</Project>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Intent.Engine;
5+
using Intent.Modelers.Eventing.Api;
6+
using Intent.Modelers.Services.Api;
7+
using Intent.Modelers.Services.EventInteractions;
8+
9+
namespace Intent.Modules.Integration.IaC.Shared.AwsSqs;
10+
11+
internal class IntegrationManager
12+
{
13+
private static IntegrationManager? _instance;
14+
15+
public static void Initialize(IApplication application)
16+
{
17+
_instance = new IntegrationManager(application);
18+
}
19+
20+
public static IntegrationManager Instance
21+
{
22+
get
23+
{
24+
if (_instance is null)
25+
{
26+
throw new InvalidOperationException("AWS SQS Integration Manager not initialized.");
27+
}
28+
return _instance;
29+
}
30+
}
31+
32+
private readonly List<MessageInfo> _publishedMessages;
33+
private readonly List<MessageInfo> _subscribedMessages;
34+
35+
private IntegrationManager(IApplication application)
36+
{
37+
var applications = application.GetSolutionConfig()
38+
.GetApplicationReferences()
39+
.Select(app => application.GetSolutionConfig().GetApplicationConfig(app.Id))
40+
.ToArray();
41+
42+
const string awsSqsModule = "Intent.Aws.Sqs";
43+
44+
// Collect published messages
45+
_publishedMessages = applications
46+
.Where(app => app.Modules.Any(x => x.ModuleId == awsSqsModule))
47+
.SelectMany(app => application.MetadataManager
48+
.GetExplicitlyPublishedMessageModels(app.Id)
49+
.Select(message => new MessageInfo(app.Id, app.Name, message, null)))
50+
.Distinct()
51+
.ToList();
52+
53+
// Collect subscribed messages
54+
_subscribedMessages = applications
55+
.Where(app => app.Modules.Any(x => x.ModuleId == awsSqsModule))
56+
.SelectMany(app => application.MetadataManager
57+
.Services(app.Id)
58+
.GetIntegrationEventHandlerModels()
59+
.SelectMany(handler => handler.IntegrationEventSubscriptions()
60+
.Select(sub => new
61+
{
62+
Message = sub.Element.AsMessageModel(),
63+
Handler = handler
64+
}))
65+
.Select(sub => new MessageInfo(app.Id, app.Name, sub.Message, sub.Handler)))
66+
.Distinct()
67+
.ToList();
68+
}
69+
70+
public IReadOnlyList<SqsMessage> GetPublishedSqsMessages(string applicationId)
71+
{
72+
return _publishedMessages
73+
.Where(p => p.ApplicationId == applicationId)
74+
.Select(s => new SqsMessage(
75+
s.ApplicationId,
76+
s.ApplicationName,
77+
s.Message,
78+
SqsMethodType.Publish))
79+
.ToList();
80+
}
81+
82+
public IReadOnlyList<SqsMessage> GetSubscribedSqsMessages(string applicationId)
83+
{
84+
return _subscribedMessages
85+
.Where(p => p.ApplicationId == applicationId)
86+
.DistinctBy(s => s.Message.Id)
87+
.Select(s => new SqsMessage(
88+
s.ApplicationId,
89+
s.ApplicationName,
90+
s.Message,
91+
SqsMethodType.Subscribe))
92+
.ToList();
93+
}
94+
95+
public IReadOnlyList<SqsItemBase> GetAggregatedPublishedSqsItems(string applicationId)
96+
{
97+
return GetPublishedSqsMessages(applicationId)
98+
.Cast<SqsItemBase>()
99+
.ToList();
100+
}
101+
102+
public IReadOnlyList<SqsItemBase> GetAggregatedSubscribedSqsItems(string applicationId)
103+
{
104+
return GetSubscribedSqsMessages(applicationId)
105+
.Cast<SqsItemBase>()
106+
.ToList();
107+
}
108+
109+
public IReadOnlyList<SqsItemBase> GetAggregatedSqsItems(string applicationId)
110+
{
111+
var duplicateCheckSet = new HashSet<string>();
112+
return GetAggregatedPublishedSqsItems(applicationId)
113+
.Concat(GetAggregatedSubscribedSqsItems(applicationId))
114+
.Where(p => duplicateCheckSet.Add($"{p.QueueName}.{p.MethodType}"))
115+
.ToList();
116+
}
117+
118+
public IReadOnlyList<Subscription<SqsItemBase>> GetAggregatedSqsSubscriptions(string applicationId)
119+
{
120+
return _subscribedMessages
121+
.Where(message => message.ApplicationId == applicationId)
122+
.Select(message => new Subscription<SqsItemBase>(
123+
message.EventHandlerModel!,
124+
new SqsMessage(
125+
applicationId,
126+
message.ApplicationName,
127+
message.Message,
128+
SqsMethodType.Subscribe)))
129+
.ToList();
130+
}
131+
132+
public record Subscription<TSubscriptionItem>(
133+
IntegrationEventHandlerModel EventHandlerModel,
134+
TSubscriptionItem SubscriptionItem);
135+
136+
private record MessageInfo(
137+
string ApplicationId,
138+
string ApplicationName,
139+
MessageModel Message,
140+
IntegrationEventHandlerModel? EventHandlerModel);
141+
}

Modules/Intent.Modules.Integration.IaC.Shared.AwsSqs/Intent.Modules.Integration.IaC.Shared.AwsSqs.projitems

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
<Import_RootNamespace>Intent.Modules.Integration.IaC.Shared.AwsSqs</Import_RootNamespace>
1010
</PropertyGroup>
1111
<ItemGroup>
12-
12+
<Compile Include="$(MSBuildThisFileDirectory)IntegrationManager.cs" />
13+
<Compile Include="$(MSBuildThisFileDirectory)SqsItemBase.cs" />
14+
<Compile Include="$(MSBuildThisFileDirectory)SqsMessage.cs" />
15+
<Compile Include="$(MSBuildThisFileDirectory)SqsMethodType.cs" />
1316
</ItemGroup>
1417
</Project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Intent.Modules.Common.Templates;
2+
3+
namespace Intent.Modules.Integration.IaC.Shared.AwsSqs;
4+
5+
internal abstract record SqsItemBase
6+
{
7+
public string ApplicationId { get; init; }
8+
public string ApplicationName { get; init; }
9+
public SqsMethodType MethodType { get; init; }
10+
public string QueueName { get; init; }
11+
public string QueueConfigurationName { get; init; }
12+
13+
public abstract string GetModelTypeName(IntentTemplateBase template);
14+
public abstract string GetSubscriberTypeName<T>(IntentTemplateBase<T> template);
15+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using Intent.Aws.Sqs.Api; // Will be created in Phase 2
3+
using Intent.Modelers.Eventing.Api;
4+
using Intent.Modules.Common.Templates;
5+
6+
namespace Intent.Modules.Integration.IaC.Shared.AwsSqs;
7+
8+
internal record SqsMessage : SqsItemBase
9+
{
10+
public SqsMessage(
11+
string applicationId,
12+
string applicationName,
13+
MessageModel messageModel,
14+
SqsMethodType methodType)
15+
{
16+
ApplicationId = applicationId;
17+
ApplicationName = applicationName;
18+
MessageModel = messageModel;
19+
MethodType = methodType;
20+
QueueName = GetQueueName(messageModel);
21+
QueueConfigurationName = GetQueueConfigurationName(messageModel);
22+
}
23+
24+
public MessageModel MessageModel { get; init; }
25+
26+
private static string GetQueueName(MessageModel message)
27+
{
28+
// Check if AWS SQS stereotype is applied
29+
if (message.HasAwsSqs())
30+
{
31+
return message.GetAwsSqs().QueueName();
32+
}
33+
34+
// Default naming convention: kebab-case, remove common suffixes
35+
var resolvedName = message.Name;
36+
resolvedName = resolvedName.RemoveSuffix("IntegrationEvent", "Event", "Message");
37+
resolvedName = resolvedName.ToKebabCase();
38+
return resolvedName;
39+
}
40+
41+
private static string GetQueueConfigurationName(MessageModel message)
42+
{
43+
const string prefix = "AwsSqs:";
44+
45+
if (message.HasAwsSqs())
46+
{
47+
var name = message.GetAwsSqs().QueueName();
48+
return prefix + name.ToPascalCase();
49+
}
50+
51+
// Default: PascalCase name
52+
var resolvedName = message.Name;
53+
resolvedName = resolvedName.RemoveSuffix("IntegrationEvent", "Event", "Message");
54+
resolvedName = resolvedName.ToPascalCase();
55+
return prefix + resolvedName;
56+
}
57+
58+
public override string GetModelTypeName(IntentTemplateBase template)
59+
{
60+
return template.GetTypeName("Intent.Eventing.Contracts.IntegrationEventMessage", MessageModel);
61+
}
62+
63+
public override string GetSubscriberTypeName<T>(IntentTemplateBase<T> template)
64+
{
65+
return $"{template.GetTypeName("Intent.Eventing.Contracts.IntegrationEventHandlerInterface")}<{GetModelTypeName(template)}>";
66+
}
67+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#nullable enable
2+
namespace Intent.Modules.Integration.IaC.Shared.AwsSqs;
3+
4+
internal enum SqsMethodType
5+
{
6+
Publish = 1,
7+
Subscribe = 2
8+
}

0 commit comments

Comments
 (0)