Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a110860
Make cache for entitiesWithoutPredictionsPerTenant tenant specific
lisajulia Jun 9, 2026
a8140a8
Merge branch 'main' into final-review-tenant-scoping
Schmarvinius Jun 10, 2026
2231d61
refactor(ai-core): make AICoreService tenant-agnostic and DI-friendly
Schmarvinius Jun 10, 2026
de4f637
feat(ai-core): restrict AICore entity APIs to current tenant
Schmarvinius Jun 10, 2026
c30080b
chore(ai-core): rename config namespace to cds.ai.core
Schmarvinius Jun 10, 2026
1eb8c33
fix(ai-core): handle null tenant in resourceGroupForTenant
Schmarvinius Jun 10, 2026
e730fa8
fix(ci): cleanup all run attempts and cds-itest resource groups
Schmarvinius Jun 10, 2026
6ebc3fd
fix(itest): align config namespace with cds.ai.core rename
Schmarvinius Jun 10, 2026
8c0197e
test(ai-core): add unit tests for tenant scoping and mock service
Schmarvinius Jun 10, 2026
7512273
chore(recommendations): add TODO for model-changed integration test
Schmarvinius Jun 10, 2026
b105dde
update cleanup
Schmarvinius Jun 11, 2026
d539f21
fix(ci): scope resource group cleanup to own job only
Schmarvinius Jun 11, 2026
cdb3967
test(ai-core): add unit tests for uncovered code paths
Schmarvinius Jun 11, 2026
6657df8
fix(ci): include cds-itest- prefix in resource group cleanup
Schmarvinius Jun 11, 2026
6e28a9d
refactor(ai-core): migrate AICoreService from CqnService to RemoteSer…
Schmarvinius Jun 11, 2026
42bcdf5
refactor(ai-core): delete AICoreApplicationServiceHandler
Schmarvinius Jun 11, 2026
fa28cda
fix(ai-core): guard service registration on AICore model presence
Schmarvinius Jun 11, 2026
ae85288
fix(test): mock CdsModel in unit tests and restore AICore model import
Schmarvinius Jun 11, 2026
62ba1d7
fix(ai-core): extend AbstractCdsDefinedService for proper RemoteServi…
Schmarvinius Jun 11, 2026
96452bd
fix(recommendations): promote cds-services-impl to compile scope
Schmarvinius Jun 11, 2026
2f60ca8
refactor(test): use real CdsRuntime in AICoreServiceConfigurationTest
Schmarvinius Jun 12, 2026
57d0d72
refactor(ai-core): remove AICORE_SERVICE_KEY env var check from bindi…
Schmarvinius Jun 12, 2026
cdd70d5
chore: exclude Mock* classes from SonarQube coverage
Schmarvinius Jun 12, 2026
c50ced3
refactor(test): use real CdsRuntime in AICoreServiceImplDeploymentIdTest
Schmarvinius Jun 12, 2026
acb2137
Merge remote-tracking branch 'origin/main' into refactor/remote-servi…
Schmarvinius Jun 12, 2026
70724c5
fix: remove duplicate detectMultiTenancy method from merge
Schmarvinius Jun 12, 2026
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
9 changes: 8 additions & 1 deletion cds-feature-ai-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,19 @@
<dependency>
<groupId>com.sap.cds</groupId>
<artifactId>cds-services-impl</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
<testResource>
<directory>src/gen/srv/src/main/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>com.sap.cds</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
package com.sap.cds.feature.aicore.api;

import com.sap.cds.services.cds.CqnService;
import com.sap.cds.services.cds.RemoteService;
import com.sap.cloud.sdk.services.openapi.apache.apiclient.ApiClient;

/**
Expand All @@ -25,10 +25,10 @@
* <p>The implementation is tenant-aware: it reads the current tenant from the {@code
* RequestContext}. Callers do not need to pass tenant identifiers explicitly.
*/
public interface AICoreService extends CqnService {
public interface AICoreService extends RemoteService {

/** Default service name under which an instance is registered in the service catalog. */
String DEFAULT_NAME = "AICore";
String DEFAULT_NAME = "AICore$Default";
Comment thread
Schmarvinius marked this conversation as resolved.

/** Qualified name of the {@code resourceGroups} entity exposed by this service. */
String RESOURCE_GROUPS = "AICore.resourceGroups";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.sap.ai.sdk.core.client.DeploymentApi;
import com.sap.ai.sdk.core.client.ResourceGroupApi;
import com.sap.cds.feature.aicore.api.AICoreService;
import com.sap.cds.feature.aicore.core.handler.AICoreApplicationServiceHandler;
import com.sap.cds.feature.aicore.core.handler.ActionHandler;
import com.sap.cds.feature.aicore.core.handler.ConfigurationHandler;
import com.sap.cds.feature.aicore.core.handler.DeploymentHandler;
Expand Down Expand Up @@ -37,19 +36,17 @@ public class AICoreServiceConfiguration implements CdsRuntimeConfiguration {

private static final Logger logger = LoggerFactory.getLogger(AICoreServiceConfiguration.class);

private static boolean hasAICoreModel(CdsRuntime runtime) {
return runtime.getCdsModel().findService("AICore").isPresent();
}

private static boolean hasAICoreBinding(CdsRuntime runtime) {
boolean hasServiceBinding =
runtime
.getEnvironment()
.getServiceBindings()
.filter(b -> ServiceBindingUtils.matches(b, "aicore"))
.findFirst()
.isPresent();
if (hasServiceBinding) {
return true;
}
String envKey = System.getenv("AICORE_SERVICE_KEY");
return envKey != null && !envKey.isBlank();
return runtime
.getEnvironment()
.getServiceBindings()
.filter(b -> ServiceBindingUtils.matches(b, "aicore"))
.findFirst()
.isPresent();
}

/**
Expand All @@ -70,6 +67,11 @@ private static boolean detectMultiTenancy(CdsRuntime runtime) {
public void services(CdsRuntimeConfigurer configurer) {
CdsRuntime runtime = configurer.getCdsRuntime();

if (!hasAICoreModel(runtime)) {
logger.debug("AICore CDS model not found in runtime model — skipping service registration.");
return;
}

boolean hasBinding = hasAICoreBinding(runtime);

boolean multiTenancyEnabled = detectMultiTenancy(runtime);
Expand Down Expand Up @@ -106,7 +108,6 @@ public void eventHandlers(CdsRuntimeConfigurer configurer) {
configurer.eventHandler(new DeploymentHandler(service));
configurer.eventHandler(new ConfigurationHandler(service));
configurer.eventHandler(new ActionHandler(service));
configurer.eventHandler(new AICoreApplicationServiceHandler(service));
logger.debug("Registered Prod AI-Core Implementation");

if (service.isMultiTenancyEnabled()) {
Expand All @@ -115,7 +116,6 @@ public void eventHandlers(CdsRuntimeConfigurer configurer) {
}
} else if (registered instanceof MockAICoreServiceImpl mockService) {
configurer.eventHandler(new MockEntityHandler());
configurer.eventHandler(new AICoreApplicationServiceHandler(mockService));
if (mockService.isMultiTenancyEnabled()) {
configurer.eventHandler(new MockAICoreSetupHandler(mockService));
logger.debug("Registered Mock AI-Core Setup Handler for MTX subscribe/unsubscribe.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
package com.sap.cds.feature.aicore.core;

import com.sap.cds.feature.aicore.api.AICoreService;
import com.sap.cds.services.impl.cds.AbstractCdsDefinedService;
import com.sap.cds.services.request.RequestContext;
import com.sap.cds.services.request.UserInfo;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cds.services.utils.services.AbstractCqnService;
import io.github.resilience4j.retry.Retry;
import java.util.Map;

Expand All @@ -16,10 +16,14 @@
* cache access, configuration, and resource group resolution. These methods are not part of the
* public {@link AICoreService} contract but are shared between the real and mock implementations.
*/
public abstract class AbstractAICoreService extends AbstractCqnService implements AICoreService {
public abstract class AbstractAICoreService extends AbstractCdsDefinedService
implements AICoreService {

/** The qualified CDS service definition name. */
private static final String CDS_DEFINITION_NAME = "AICore";

protected AbstractAICoreService(String name, CdsRuntime runtime) {
super(name, runtime);
super(name, CDS_DEFINITION_NAME, runtime);
}

/** Returns the {@link CdsRuntime} that this service was created with. */
Expand Down

This file was deleted.

Loading
Loading