Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public boolean isXtmComposerReachable() {
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successful retrieval")})
public List<XtmComposerInstanceOutput> getAllConnectorInstances(
@PathVariable @NotBlank final String xtmComposerId) {
return orchestrationService.findConnectorInstancesManagedByComposer(xtmComposerId);
return orchestrationService.findActiveConnectorInstancesManagedByComposer(xtmComposerId);
}

@PutMapping(
Expand Down Expand Up @@ -130,4 +130,25 @@ public XtmComposerInstanceOutput receiveConnectorInstanceHealthCheck(
return orchestrationService.patchConnectorInstanceHealthCheck(
xtmComposerId, connectorInstanceId, input);
}

@DeleteMapping(
value = XTMCOMPOSER_URI + "/{xtmComposerId}/connector-instances/{connectorInstanceId}")
@Operation(
summary = "Delete connector instances and remove associated connector",
description =
"""
Receives a deletion notification from XtmComposer for a connector instance.
This triggers:
- Removal of the associated injector, collector, or executor
- Permanent deletion of the connector instance from OpenAEV database
""")
@RBAC(actionPerformed = Action.DELETE, resourceType = ResourceType.CATALOG)
@ApiResponses(
value = {@ApiResponse(responseCode = "200", description = "Successfully delete connector")})
public void notifyConnectorDeleted(
@PathVariable @NotBlank final String xtmComposerId,
@PathVariable @NotBlank final String connectorInstanceId) {
orchestrationService.deleteConnectorInstanceAndAssociatedConnector(
xtmComposerId, connectorInstanceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,11 @@ protected Executor getConnectorById(String executorId) {

@Override
protected ExecutorOutput mapToOutput(
Executor executor, CatalogConnector catalogConnector, boolean isVerified) {
return executorMapper.toExecutorOutput(executor, catalogConnector, isVerified);
Executor executor,
CatalogConnector catalogConnector,
ConnectorInstance instance,
boolean isVerified) {
return executorMapper.toExecutorOutput(executor, catalogConnector, instance, isVerified);
}

@Override
Expand Down Expand Up @@ -241,4 +244,13 @@ public List<Agent> manageWithoutPlatformAgents(List<Agent> agents, InjectStatus
}
return agents;
}

/**
* Delete an executor by ID
*
* @param id the executor ID to delete
*/
public void deleteById(String id) {
executorRepository.deleteById(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.openaev.migration;

import java.sql.Statement;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import org.springframework.stereotype.Component;

@Component
public class V4_59__Add_deleting_requested_connector_status extends BaseJavaMigration {
@Override
public void migrate(Context context) throws Exception {
try (Statement select = context.getConnection().createStatement()) {
select.execute("ALTER TYPE connector_instance_requested_status_type ADD VALUE 'deleting'; ");
select.execute(
"""
ALTER TABLE connector_instances
ADD COLUMN connector_instance_enable_deletion boolean DEFAULT FALSE;
""");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ public class CollectorApi extends RestBehavior {
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = CollectorOutput.class))))
public Iterable<CollectorOutput> collectors(
@Parameter(
name = "includeNext",
description = "Include collectors pending deployment",
required = false)
@Parameter(name = "includeNext", description = "Include collectors pending deployment")
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The removal of required = false from the @parameter annotation is unnecessary since the corresponding @RequestParam already specifies required = false. This change doesn't add value and differs from the original explicit declaration.

Suggested change
@Parameter(name = "includeNext", description = "Include collectors pending deployment")
@Parameter(
name = "includeNext",
description = "Include collectors pending deployment",
required = false)

Copilot uses AI. Check for mistakes.
@RequestParam(value = "include_next", required = false, defaultValue = "false")
boolean includeNext) {
return collectorService.collectorsOutput(includeNext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openaev.rest.catalog_connector.dto.CatalogConnectorSimpleOutput;
import io.openaev.rest.connector_instance.dto.ConnectorInstanceOutput;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotBlank;
import java.time.Instant;
import lombok.Builder;
Expand Down Expand Up @@ -35,4 +37,8 @@ public class CollectorOutput {

@JsonProperty("is_verified")
private boolean verified = false;

@JsonProperty("connector_instance")
@Nullable
private ConnectorInstanceOutput connectorInstance;
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ protected Collector getConnectorById(String collectorId) {

@Override
protected CollectorOutput mapToOutput(
Collector collector, CatalogConnector catalogConnector, boolean isVerified) {
return collectorMapper.toCollectorOutput(collector, catalogConnector, isVerified);
Collector collector,
CatalogConnector catalogConnector,
ConnectorInstance instance,
boolean isVerified) {
return collectorMapper.toCollectorOutput(collector, catalogConnector, instance, isVerified);
}

@Override
Expand Down Expand Up @@ -161,6 +164,15 @@ public Collector updateCollectorState(Collector collectorToUpdate, ObjectNode ne
return collectorRepository.save(collectorToUpdate);
}

/**
* Delete a collector by ID
*
* @param id the collector ID to delete
*/
public void deleteById(String id) {
collectorRepository.deleteById(id);
}

// -- ACTION --

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,4 @@ public ConnectorInstance updateRequestedStatus(
return orchestrationService.updateRequestedStatus(
connectorInstanceId, input.getRequestedStatus());
}

@DeleteMapping(value = CONNECTOR_INSTANCE_URI + "/{connectorInstanceId}")
@Operation(summary = "Delete connector instance")
@RBAC(actionPerformed = Action.DELETE, resourceType = ResourceType.CATALOG)
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "Successfully deleted connector instance")
})
public void deleteConnectorInstance(@PathVariable @NotBlank final String connectorInstanceId) {
connectorInstanceService.deleteById(connectorInstanceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ public class ConnectorInstanceOutput {

@JsonProperty("connector_instance_requested_status")
private ConnectorInstance.REQUESTED_STATUS_TYPE requestedStatus;

@JsonProperty("connector_instance_enable_deletion")
private boolean enableDeletion;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openaev.rest.catalog_connector.dto.CatalogConnectorSimpleOutput;
import io.openaev.rest.connector_instance.dto.ConnectorInstanceOutput;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotBlank;
import java.time.Instant;
import lombok.Builder;
Expand Down Expand Up @@ -32,4 +34,8 @@ public class ExecutorOutput {

@JsonProperty("is_verified")
private boolean verified = false;

@JsonProperty("connector_instance")
@Nullable
private ConnectorInstanceOutput connectorInstance;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openaev.rest.catalog_connector.dto.CatalogConnectorSimpleOutput;
import io.openaev.rest.connector_instance.dto.ConnectorInstanceOutput;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotBlank;
import java.time.Instant;
import lombok.Builder;
Expand Down Expand Up @@ -34,4 +36,8 @@ public class InjectorOutput {

@JsonProperty("injector_updated_at")
private Instant updatedAt;

@JsonProperty("connector_instance")
@Nullable
private ConnectorInstanceOutput connectorInstance;
}
16 changes: 14 additions & 2 deletions openaev-api/src/main/java/io/openaev/service/InjectorService.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,11 @@ protected Injector getConnectorById(String injectorId) {

@Override
protected InjectorOutput mapToOutput(
Injector injector, CatalogConnector catalogConnector, boolean isVerified) {
return injectorMapper.toInjectorOutput(injector, catalogConnector, isVerified);
Injector injector,
CatalogConnector catalogConnector,
ConnectorInstance instance,
boolean isVerified) {
return injectorMapper.toInjectorOutput(injector, catalogConnector, instance, isVerified);
}

@Override
Expand Down Expand Up @@ -341,4 +344,13 @@ public Injector updateInjector(
injectorContractRepository.saveAll(toCreates);
return injectorRepository.save(injector);
}

/**
* Delete an injector by ID
*
* @param id the injector ID to delete
*/
public void deleteById(String id) {
injectorRepository.deleteById(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.openaev.rest.connector_instance.dto.ConnectorInstanceHealthInput;
import io.openaev.rest.connector_instance.dto.ConnectorInstanceOutput;
import io.openaev.rest.connector_instance.dto.CreateConnectorInstanceInput;
import io.openaev.rest.exception.BadRequestException;
import io.openaev.service.connectors.ConnectorOrchestrationService;
import io.openaev.utils.mapper.ConnectorInstanceMapper;
import jakarta.persistence.EntityNotFoundException;
Expand All @@ -38,12 +39,12 @@ public class ConnectorInstanceService {
private final EncryptionFactory encryptionFactory;

/**
* Retrieves all connector instances managed by XtmComposer with their configurations.
* Retrieves all active connector instances managed by XtmComposer with their configurations.
*
* @return the list of connector instances managed by XtmComposer
*/
public List<ConnectorInstance> connectorInstancesManagedByXtmComposer() {
return connectorInstanceRepository.findAllManagedByXtmComposerAndConfiguration();
public List<ConnectorInstance> activeConnectorInstancesManagedByXtmComposer() {
return connectorInstanceRepository.findAllActiveManagedByXtmComposerAndConfiguration();
}

/**
Expand Down Expand Up @@ -142,7 +143,12 @@ public ConnectorInstance updateCurrentStatus(
* @return the connector instance updated
*/
public ConnectorInstance updateRequestedStatus(
ConnectorInstance instance, ConnectorInstance.REQUESTED_STATUS_TYPE newRequestedStatus) {
ConnectorInstance instance, ConnectorInstance.REQUESTED_STATUS_TYPE newRequestedStatus)
throws BadRequestException {
if (ConnectorInstance.REQUESTED_STATUS_TYPE.deleting.equals(newRequestedStatus)
&& !instance.isEnableDeletion()) {
throw new BadRequestException("Deletion request is not enabled for this connector instance");
}
instance.setRequestedStatus(newRequestedStatus);
return this.save(instance);
}
Expand Down Expand Up @@ -202,6 +208,7 @@ private ConnectorInstance buildNewConnectorInstanceFromCatalog(
newInstance.setRequestedStatus(ConnectorInstance.REQUESTED_STATUS_TYPE.stopping);
newInstance.setCurrentStatus(ConnectorInstance.CURRENT_STATUS_TYPE.stopped);
newInstance.setSource(ConnectorInstance.SOURCE.CATALOG_DEPLOYMENT);
newInstance.setEnableDeletion(!catalogConnector.isManagerSupported());
return newInstance;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ protected AbstractConnectorService(
protected abstract T getConnectorById(String id);

protected abstract Output mapToOutput(
T connector, CatalogConnector catalogConnector, boolean isVerified);
T connector,
CatalogConnector catalogConnector,
ConnectorInstance instance,
boolean isVerified);

protected abstract T createNewConnector();

private String getConnectorIdFromInstance(ConnectorInstance instance) {
public String getConnectorIdFromInstance(ConnectorInstance instance) {
return instance.getConfigurations().stream()
.filter(c -> this.connectorType.getIdKeyName().equals(c.getKey()))
.map(c -> c.getValue().asText())
Expand Down Expand Up @@ -69,7 +72,7 @@ private Output toConnectorOutput(T connector, Map<String, ConnectorInstance> ins
: catalogConnectorService
.findBySlug(connector.getType().replace("openaev_", ""))
.orElse(null);
return mapToOutput(connector, catalogConnector, isVerified);
return mapToOutput(connector, catalogConnector, instance, isVerified);
}

private T createExternalCollector(String collectorId, ConnectorInstance instance) {
Expand Down Expand Up @@ -112,7 +115,12 @@ public Iterable<Output> getConnectorsOutput(boolean includeNext) {
.forEach(
entry -> {
T newConnector = createExternalCollector(entry.getKey(), entry.getValue());
result.add(mapToOutput(newConnector, entry.getValue().getCatalogConnector(), true));
result.add(
mapToOutput(
newConnector,
entry.getValue().getCatalogConnector(),
entry.getValue(),
true));
});
}

Expand Down
Loading