diff --git a/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java
index e69b1f30efe..838cd59eedf 100644
--- a/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java
+++ b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java
@@ -27,7 +27,7 @@
*/
@NoArgsConstructor
@AllArgsConstructor
-@Builder
+@Builder(toBuilder = true)
@Data
public class Integration {
diff --git a/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Token.java b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Token.java
index 5b90c06ec48..6876814d2a6 100644
--- a/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Token.java
+++ b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Token.java
@@ -17,11 +17,17 @@
import java.util.Date;
import java.util.Objects;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
/**
* @author Azize ELAMRANI (azize.elamrani at graviteesource.com)
* @author GraviteeSource Team
*/
+@Builder(toBuilder = true)
+@AllArgsConstructor
+@NoArgsConstructor
public class Token {
public enum AuditEvent implements Audit.AuditEvent {
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-coverage/pom.xml b/gravitee-apim-rest-api/gravitee-apim-rest-api-coverage/pom.xml
index b5e25f9bb4e..dba3e61914e 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-coverage/pom.xml
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-coverage/pom.xml
@@ -44,6 +44,12 @@
${project.version}
+
+ io.gravitee.apim.rest.api
+ gravitee-apim-rest-api-integration-controller
+ ${project.version}
+
+
io.gravitee.apim.rest.api.idp
gravitee-apim-rest-api-idp-api
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/pom.xml b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/pom.xml
new file mode 100644
index 00000000000..58c57722a35
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/pom.xml
@@ -0,0 +1,86 @@
+
+
+
+ 4.0.0
+
+ io.gravitee.apim.rest.api
+ gravitee-apim-rest-api
+ ${revision}${sha1}${changelist}
+
+
+ gravitee-apim-rest-api-integration-controller
+ jar
+
+ Gravitee.io APIM - Management API - Integration Controller
+ Controller interacting with Integration Agents
+
+
+
+
+ io.gravitee.exchange
+ gravitee-exchange-api
+ ${gravitee-exchange.version}
+
+
+ io.gravitee.exchange
+ gravitee-exchange-controller-core
+ ${gravitee-exchange.version}
+
+
+ io.gravitee.exchange
+ gravitee-exchange-controller-websocket
+ ${gravitee-exchange.version}
+
+
+ io.gravitee.integration
+ gravitee-integration-api
+ ${gravitee-integration-api.version}
+
+
+ io.gravitee.apim.rest.api
+ gravitee-apim-rest-api-service
+ ${project.version}
+ provided
+
+
+
+
+ io.reactivex.rxjava3
+ rxjava
+ provided
+
+
+ org.slf4j
+ slf4j-api
+ provided
+
+
+
+
+ io.gravitee.apim.rest.api
+ gravitee-apim-rest-api-service
+ ${project.version}
+ test-jar
+ test
+
+
+
+
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/IntegrationCommandContext.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/IntegrationCommandContext.java
new file mode 100644
index 00000000000..e89268a2462
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/IntegrationCommandContext.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.command;
+
+import io.gravitee.exchange.api.controller.ControllerCommandContext;
+import java.util.Set;
+
+public record IntegrationCommandContext(boolean valid) implements ControllerCommandContext {
+ @Override
+ public boolean isValid() {
+ return valid;
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/IntegrationControllerCommandHandlerFactory.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/IntegrationControllerCommandHandlerFactory.java
new file mode 100644
index 00000000000..1e68277776b
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/IntegrationControllerCommandHandlerFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.command;
+
+import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService;
+import io.gravitee.exchange.api.command.Command;
+import io.gravitee.exchange.api.command.CommandAdapter;
+import io.gravitee.exchange.api.command.CommandHandler;
+import io.gravitee.exchange.api.command.Reply;
+import io.gravitee.exchange.api.command.ReplyAdapter;
+import io.gravitee.exchange.api.controller.ControllerCommandContext;
+import io.gravitee.exchange.api.controller.ControllerCommandHandlersFactory;
+import io.gravitee.exchange.api.websocket.protocol.ProtocolVersion;
+import io.gravitee.integration.controller.command.hello.HelloCommandHandler;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class IntegrationControllerCommandHandlerFactory implements ControllerCommandHandlersFactory {
+
+ private final IntegrationCrudService integrationCrudService;
+
+ @Override
+ public List, ? extends Reply>>> buildCommandHandlers(
+ final ControllerCommandContext controllerCommandContext
+ ) {
+ return List.of(new HelloCommandHandler(integrationCrudService));
+ }
+
+ @Override
+ public List, ? extends Command>, ? extends Reply>>> buildCommandAdapters(
+ ControllerCommandContext controllerCommandContext,
+ ProtocolVersion protocolVersion
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public List, ? extends Reply>>> buildReplyAdapters(
+ ControllerCommandContext controllerCommandContext,
+ ProtocolVersion protocolVersion
+ ) {
+ return List.of();
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/hello/HelloCommandHandler.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/hello/HelloCommandHandler.java
new file mode 100644
index 00000000000..5612cac4918
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/command/hello/HelloCommandHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.command.hello;
+
+import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService;
+import io.gravitee.exchange.api.command.CommandHandler;
+import io.gravitee.exchange.api.command.hello.HelloReply;
+import io.gravitee.exchange.api.command.hello.HelloReplyPayload;
+import io.gravitee.integration.api.command.IntegrationCommandType;
+import io.gravitee.integration.api.command.hello.HelloCommand;
+import io.gravitee.integration.api.command.hello.HelloCommandPayload;
+import io.reactivex.rxjava3.core.Single;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@RequiredArgsConstructor
+@Slf4j
+public class HelloCommandHandler implements CommandHandler {
+
+ private final IntegrationCrudService integrationCrudService;
+
+ @Override
+ public String supportType() {
+ return IntegrationCommandType.HELLO.name();
+ }
+
+ @Override
+ public Single handle(HelloCommand command) {
+ return Single
+ .fromCallable(() -> {
+ HelloCommandPayload payload = command.getPayload();
+
+ return integrationCrudService
+ .findById(payload.getTargetId())
+ .map(integration -> {
+ if (integration.getProvider().equals(payload.getProvider())) {
+ return new HelloReply(command.getId(), HelloReplyPayload.builder().targetId(integration.getId()).build());
+ }
+ return new HelloReply(
+ command.getId(),
+ String.format(
+ "Integration [id=%s] does not match. Expected provider [provider=%s]",
+ integration.getId(),
+ integration.getProvider()
+ )
+ );
+ })
+ .orElse(new HelloReply(command.getId(), String.format("Integration [id=%s] not found", payload.getTargetId())));
+ })
+ .doOnError(throwable ->
+ log.error("Unable to process hello command payload for target [{}]", command.getPayload().getTargetId(), throwable)
+ )
+ .onErrorReturn(throwable -> new HelloReply(command.getId(), throwable.getMessage()));
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/spring/IntegrationControllerConfiguration.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/spring/IntegrationControllerConfiguration.java
new file mode 100644
index 00000000000..c9d1141d769
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/spring/IntegrationControllerConfiguration.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.spring;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService;
+import io.gravitee.apim.core.user.crud_service.UserCrudService;
+import io.gravitee.exchange.api.configuration.IdentifyConfiguration;
+import io.gravitee.exchange.api.controller.ControllerCommandHandlersFactory;
+import io.gravitee.exchange.api.controller.ExchangeController;
+import io.gravitee.exchange.api.websocket.command.ExchangeSerDe;
+import io.gravitee.exchange.controller.websocket.WebSocketExchangeController;
+import io.gravitee.exchange.controller.websocket.auth.WebSocketControllerAuthentication;
+import io.gravitee.integration.api.websocket.command.IntegrationExchangeSerDe;
+import io.gravitee.integration.controller.command.IntegrationControllerCommandHandlerFactory;
+import io.gravitee.integration.controller.websocket.auth.IntegrationWebsocketControllerAuthentication;
+import io.gravitee.node.api.cache.CacheManager;
+import io.gravitee.node.api.certificate.KeyStoreLoaderFactoryRegistry;
+import io.gravitee.node.api.certificate.KeyStoreLoaderOptions;
+import io.gravitee.node.api.certificate.TrustStoreLoaderOptions;
+import io.gravitee.node.api.cluster.ClusterManager;
+import io.gravitee.rest.api.service.TokenService;
+import io.vertx.rxjava3.core.Vertx;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.core.env.Environment;
+
+@Configuration
+public class IntegrationControllerConfiguration {
+
+ @Bean("integrationWebsocketControllerAuthentication")
+ public IntegrationWebsocketControllerAuthentication integrationWebsocketControllerAuthentication(
+ final TokenService tokenService,
+ final UserCrudService userCrudService
+ ) {
+ return new IntegrationWebsocketControllerAuthentication(tokenService, userCrudService);
+ }
+
+ @Bean("integrationExchangeSerDe")
+ public IntegrationExchangeSerDe integrationExchangeSerDe() {
+ return new IntegrationExchangeSerDe(objectMapper());
+ }
+
+ @Bean("integrationIdentifyConfiguration")
+ public IdentifyConfiguration integrationPrefixConfiguration(final Environment environment) {
+ return new IdentifyConfiguration(environment, "integration");
+ }
+
+ @Bean("integrationControllerCommandHandlerFactory")
+ public IntegrationControllerCommandHandlerFactory integrationControllerCommandHandlerFactory(
+ final IntegrationCrudService integrationCrudService
+ ) {
+ return new IntegrationControllerCommandHandlerFactory(integrationCrudService);
+ }
+
+ @Bean("integrationExchangeController")
+ public ExchangeController integrationExchangeController(
+ final @Lazy ClusterManager clusterManager,
+ final @Lazy CacheManager cacheManager,
+ final Vertx vertx,
+ final KeyStoreLoaderFactoryRegistry keyStoreLoaderFactoryRegistry,
+ final KeyStoreLoaderFactoryRegistry trustStoreLoaderFactoryRegistry,
+ final @Qualifier("integrationIdentifyConfiguration") IdentifyConfiguration identifyConfiguration,
+ final @Qualifier(
+ "integrationWebsocketControllerAuthentication"
+ ) WebSocketControllerAuthentication> integrationWebsocketControllerAuthentication,
+ final @Qualifier(
+ "integrationControllerCommandHandlerFactory"
+ ) ControllerCommandHandlersFactory integrationControllerCommandHandlerFactory,
+ final @Qualifier("integrationExchangeSerDe") ExchangeSerDe integrationExchangeSerDe
+ ) {
+ return new WebSocketExchangeController(
+ identifyConfiguration,
+ clusterManager,
+ cacheManager,
+ vertx,
+ keyStoreLoaderFactoryRegistry,
+ trustStoreLoaderFactoryRegistry,
+ integrationWebsocketControllerAuthentication,
+ integrationControllerCommandHandlerFactory,
+ integrationExchangeSerDe
+ );
+ }
+
+ public ObjectMapper objectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(new JavaTimeModule());
+ mapper.disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ return mapper;
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/websocket/auth/IntegrationWebsocketControllerAuthentication.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/websocket/auth/IntegrationWebsocketControllerAuthentication.java
new file mode 100644
index 00000000000..1c8f471958d
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/main/java/io/gravitee/integration/controller/websocket/auth/IntegrationWebsocketControllerAuthentication.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.websocket.auth;
+
+import io.gravitee.apim.core.user.crud_service.UserCrudService;
+import io.gravitee.exchange.controller.websocket.auth.WebSocketControllerAuthentication;
+import io.gravitee.integration.controller.command.IntegrationCommandContext;
+import io.gravitee.repository.management.model.Token;
+import io.gravitee.rest.api.service.TokenService;
+import io.gravitee.rest.api.service.exceptions.UserNotFoundException;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.vertx.rxjava3.core.http.HttpServerRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+@Slf4j
+@Service("integrationWebsocketControllerAuthentication")
+@RequiredArgsConstructor
+public class IntegrationWebsocketControllerAuthentication implements WebSocketControllerAuthentication {
+
+ public static final String AUTHORIZATION_HEADER = HttpHeaderNames.AUTHORIZATION.toString();
+ public static final String AUTHORIZATION_HEADER_BEARER = "bearer";
+ private final TokenService tokenService;
+ private final UserCrudService userCrudService;
+
+ @Override
+ public IntegrationCommandContext authenticate(final HttpServerRequest httpServerRequest) {
+ String header = httpServerRequest.headers().get(AUTHORIZATION_HEADER);
+ if (header != null) {
+ final String tokenValue = header.substring(AUTHORIZATION_HEADER_BEARER.length()).trim();
+ try {
+ final Token token = tokenService.findByToken(tokenValue);
+ return userCrudService
+ .findBaseUserById(token.getReferenceId())
+ .map(user -> new IntegrationCommandContext(true))
+ .orElseThrow(() -> new UserNotFoundException(token.getReferenceId()));
+ } catch (Exception e) {
+ log.warn("Unable to authenticate incoming websocket controller request");
+ }
+ }
+ log.warn("No authentication header in the incoming websocket controller request");
+ return new IntegrationCommandContext(false);
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/test/java/io/gravitee/integration/controller/command/hello/HelloCommandHandlerTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/test/java/io/gravitee/integration/controller/command/hello/HelloCommandHandlerTest.java
new file mode 100644
index 00000000000..bb828feee63
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/test/java/io/gravitee/integration/controller/command/hello/HelloCommandHandlerTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.command.hello;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
+
+import fixtures.core.model.IntegrationFixture;
+import inmemory.IntegrationCrudServiceInMemory;
+import io.gravitee.apim.core.exception.TechnicalDomainException;
+import io.gravitee.apim.core.integration.model.Integration;
+import io.gravitee.exchange.api.command.CommandStatus;
+import io.gravitee.exchange.api.command.hello.HelloReplyPayload;
+import io.gravitee.integration.api.command.hello.HelloCommand;
+import io.gravitee.integration.api.command.hello.HelloCommandPayload;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+class HelloCommandHandlerTest {
+
+ private static final String COMMAND_ID = "command-id";
+ private static final String INTEGRATION_ID = "my-integration-id";
+ private static final String INTEGRATION_PROVIDER = "amazon";
+
+ private static final HelloCommand COMMAND = new HelloCommand(
+ COMMAND_ID,
+ HelloCommandPayload.builder().targetId(INTEGRATION_ID).provider(INTEGRATION_PROVIDER).build()
+ );
+
+ IntegrationCrudServiceInMemory integrationCrudServiceInMemory = new IntegrationCrudServiceInMemory();
+ HelloCommandHandler commandHandler;
+
+ @BeforeEach
+ void setUp() {
+ commandHandler = new HelloCommandHandler(integrationCrudServiceInMemory);
+ }
+
+ @AfterEach
+ void tearDown() {
+ integrationCrudServiceInMemory.reset();
+ }
+
+ @Test
+ void should_reply_succeeded_when_integration_exists() {
+ var integration = givenIntegration(
+ IntegrationFixture.anIntegration().toBuilder().id(INTEGRATION_ID).provider(INTEGRATION_PROVIDER).build()
+ );
+
+ commandHandler
+ .handle(COMMAND)
+ .test()
+ .awaitDone(10, TimeUnit.SECONDS)
+ .assertValue(reply -> {
+ SoftAssertions.assertSoftly(soft -> {
+ soft.assertThat(reply.getCommandStatus()).isEqualTo(CommandStatus.SUCCEEDED);
+ soft.assertThat(reply.getCommandId()).isEqualTo(COMMAND_ID);
+ soft.assertThat(reply.getPayload()).isEqualTo(HelloReplyPayload.builder().targetId(integration.getId()).build());
+ });
+
+ return true;
+ })
+ .assertNoErrors();
+ }
+
+ @Test
+ void should_reply_error_when_integration_does_not_exist() {
+ commandHandler
+ .handle(COMMAND)
+ .test()
+ .awaitDone(10, TimeUnit.SECONDS)
+ .assertValue(reply -> {
+ SoftAssertions.assertSoftly(soft -> {
+ soft.assertThat(reply.getCommandStatus()).isEqualTo(CommandStatus.ERROR);
+ soft.assertThat(reply.getCommandId()).isEqualTo(COMMAND_ID);
+ soft.assertThat(reply.getErrorDetails()).isEqualTo("Integration [id=my-integration-id] not found");
+ });
+
+ return true;
+ })
+ .assertNoErrors();
+ }
+
+ @Test
+ void should_reply_error_when_integration_exist_but_provider_mismatch() {
+ givenIntegration(IntegrationFixture.anIntegration().toBuilder().id("my-integration-id").provider("other").build());
+
+ commandHandler
+ .handle(COMMAND)
+ .test()
+ .awaitDone(10, TimeUnit.SECONDS)
+ .assertValue(reply -> {
+ SoftAssertions.assertSoftly(soft -> {
+ soft.assertThat(reply.getCommandStatus()).isEqualTo(CommandStatus.ERROR);
+ soft.assertThat(reply.getCommandId()).isEqualTo(COMMAND_ID);
+ soft
+ .assertThat(reply.getErrorDetails())
+ .isEqualTo("Integration [id=my-integration-id] does not match. Expected provider [provider=other]");
+ });
+
+ return true;
+ })
+ .assertNoErrors();
+ }
+
+ @Test
+ void should_reply_error_when_exception_occurs() {
+ var spied = Mockito.spy(integrationCrudServiceInMemory);
+ lenient().when(spied.findById(any())).thenThrow(new TechnicalDomainException("error"));
+ commandHandler = new HelloCommandHandler(spied);
+
+ commandHandler
+ .handle(COMMAND)
+ .test()
+ .awaitDone(10, TimeUnit.SECONDS)
+ .assertValue(reply -> {
+ SoftAssertions.assertSoftly(soft -> {
+ soft.assertThat(reply.getCommandStatus()).isEqualTo(CommandStatus.ERROR);
+ soft.assertThat(reply.getCommandId()).isEqualTo(COMMAND_ID);
+ soft.assertThat(reply.getErrorDetails()).isEqualTo("error");
+ });
+
+ return true;
+ })
+ .assertNoErrors();
+ }
+
+ private Integration givenIntegration(Integration integration) {
+ integrationCrudServiceInMemory.initWith(List.of(integration));
+ return integration;
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/test/java/io/gravitee/integration/controller/websocket/auth/IntegrationWebsocketControllerAuthenticationTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/test/java/io/gravitee/integration/controller/websocket/auth/IntegrationWebsocketControllerAuthenticationTest.java
new file mode 100644
index 00000000000..d2875df3e51
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-integration-controller/src/test/java/io/gravitee/integration/controller/websocket/auth/IntegrationWebsocketControllerAuthenticationTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.integration.controller.websocket.auth;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
+
+import inmemory.UserCrudServiceInMemory;
+import io.gravitee.apim.core.user.model.BaseUserEntity;
+import io.gravitee.integration.controller.command.IntegrationCommandContext;
+import io.gravitee.repository.management.model.Token;
+import io.gravitee.rest.api.service.TokenService;
+import io.gravitee.rest.api.service.exceptions.TokenNotFoundException;
+import io.vertx.rxjava3.core.MultiMap;
+import io.vertx.rxjava3.core.http.HttpHeaders;
+import io.vertx.rxjava3.core.http.HttpServerRequest;
+import java.util.List;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class IntegrationWebsocketControllerAuthenticationTest {
+
+ private static final String TOKEN_VALUE = "my-token-value";
+
+ @Mock
+ TokenService tokenService;
+
+ @Mock
+ HttpServerRequest request;
+
+ UserCrudServiceInMemory userCrudServiceInMemory = new UserCrudServiceInMemory();
+
+ IntegrationWebsocketControllerAuthentication authentication;
+
+ @BeforeEach
+ void setUp() {
+ authentication = new IntegrationWebsocketControllerAuthentication(tokenService, userCrudServiceInMemory);
+
+ MultiMap requestHeaders = HttpHeaders.headers();
+ requestHeaders.add(IntegrationWebsocketControllerAuthentication.AUTHORIZATION_HEADER, "bearer " + TOKEN_VALUE);
+ lenient().when(request.headers()).thenReturn(requestHeaders);
+ }
+
+ @AfterEach
+ void tearDown() {
+ userCrudServiceInMemory.reset();
+ }
+
+ @Test
+ void should_return_a_valid_IntegrationCommandContext_when_authentication_succeed() {
+ var token = givenToken(Token.builder().token(TOKEN_VALUE).referenceId("user-id").build());
+ givenUser(BaseUserEntity.builder().id(token.getReferenceId()).build());
+
+ var result = authentication.authenticate(request);
+
+ assertThat(result).isEqualTo(new IntegrationCommandContext(true));
+ }
+
+ @Test
+ void should_return_an_invalid_IntegrationCommandContext_when_no_token_found() {
+ givenNoToken();
+
+ var result = authentication.authenticate(request);
+
+ assertThat(result).isEqualTo(new IntegrationCommandContext(false));
+ }
+
+ @Test
+ void should_return_an_invalid_IntegrationCommandContext_when_no_user_found() {
+ givenToken(Token.builder().token(TOKEN_VALUE).referenceId("user-id").build());
+
+ var result = authentication.authenticate(request);
+
+ assertThat(result).isEqualTo(new IntegrationCommandContext(false));
+ }
+
+ @Test
+ void should_return_an_invalid_IntegrationCommandContext_when_no_authorization_headers() {
+ lenient().when(request.headers()).thenReturn(HttpHeaders.headers());
+
+ var result = authentication.authenticate(request);
+
+ assertThat(result).isEqualTo(new IntegrationCommandContext(false));
+ }
+
+ private Token givenToken(Token token) {
+ lenient().when(tokenService.findByToken(token.getToken())).thenReturn(token);
+ return token;
+ }
+
+ private void givenNoToken() {
+ lenient().when(tokenService.findByToken(any())).thenThrow(new TokenNotFoundException("token"));
+ }
+
+ private void givenUser(BaseUserEntity user) {
+ userCrudServiceInMemory.initWith(List.of(user));
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java
index 04070feb702..fdff9446ed2 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java
@@ -16,6 +16,7 @@
package io.gravitee.apim.core.integration.crud_service;
import io.gravitee.apim.core.integration.model.Integration;
+import java.util.Optional;
/**
* @author Remi Baptiste (remi.baptiste at graviteesource.com)
@@ -23,4 +24,6 @@
*/
public interface IntegrationCrudService {
Integration create(Integration integration);
+
+ Optional findById(String id);
}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java
index 7e3d26e8214..87e3bec21ca 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java
@@ -15,7 +15,6 @@
*/
package io.gravitee.apim.infra.crud_service.integration;
-import io.gravitee.apim.core.exception.TechnicalDomainException;
import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService;
import io.gravitee.apim.core.integration.model.Integration;
import io.gravitee.apim.infra.adapter.IntegrationAdapter;
@@ -23,6 +22,7 @@
import io.gravitee.repository.management.api.IntegrationRepository;
import io.gravitee.rest.api.service.exceptions.TechnicalManagementException;
import io.gravitee.rest.api.service.impl.AbstractService;
+import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@@ -50,4 +50,13 @@ public Integration create(Integration integration) {
throw new TechnicalManagementException("Error when creating Integration: " + integration.getName(), e);
}
}
+
+ @Override
+ public Optional findById(String id) {
+ try {
+ return integrationRepository.findById(id).map(IntegrationAdapter.INSTANCE::toEntity);
+ } catch (TechnicalException e) {
+ throw new TechnicalManagementException("An error occurs while trying to find the integration: " + id, e);
+ }
+ }
}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/DefaultOrganizationAdminRoleInitializer.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/DefaultOrganizationAdminRoleInitializer.java
index 4c5c36ab21b..bb5e4702413 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/DefaultOrganizationAdminRoleInitializer.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/DefaultOrganizationAdminRoleInitializer.java
@@ -15,6 +15,7 @@
*/
package io.gravitee.rest.api.service.impl.upgrade.initializer;
+import io.gravitee.rest.api.model.permissions.EnvironmentPermission;
import io.gravitee.rest.api.model.permissions.OrganizationPermission;
import io.gravitee.rest.api.model.permissions.RoleScope;
import io.gravitee.rest.api.model.permissions.SystemRole;
@@ -45,6 +46,14 @@ protected void initializeOrganization(ExecutionContext executionContext) {
OrganizationPermission.values(),
executionContext.getOrganizationId()
);
+
+ roleService.createOrUpdateSystemRole(
+ executionContext,
+ SystemRole.ADMIN,
+ RoleScope.ENVIRONMENT,
+ EnvironmentPermission.values(),
+ executionContext.getOrganizationId()
+ );
}
@Override
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/InitializerOrder.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/InitializerOrder.java
index 292cd2ee089..bb6d9623169 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/InitializerOrder.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/InitializerOrder.java
@@ -37,4 +37,5 @@ private InitializerOrder() {}
public static final int IDENTITY_PROVIDER_ACTIVATION_INITIALIZER = 400;
public static final int IDENTITY_PROVIDER_INITIALIZER = 350;
public static final int SEARCH_INDEX_INITIALIZER = 250;
+ public static final int INTEGRATION_CONTROLLER_INITIALIZER = 400;
}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/IntegrationControllerInitializer.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/IntegrationControllerInitializer.java
new file mode 100644
index 00000000000..1a580671753
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/upgrade/initializer/IntegrationControllerInitializer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.gravitee.rest.api.service.impl.upgrade.initializer;
+
+import io.gravitee.exchange.api.controller.ExchangeController;
+import io.gravitee.node.api.initializer.Initializer;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+public class IntegrationControllerInitializer implements Initializer {
+
+ @Autowired
+ @Qualifier("integrationExchangeController")
+ private ExchangeController integrationExchangeController;
+
+ @Override
+ public boolean initialize() {
+ try {
+ // TODO check license before starting controller
+ integrationExchangeController.start();
+ log.info("Integrations started.");
+ } catch (Exception e) {
+ log.error("Fail to start Integration Controller", e);
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+
+ @Override
+ public int getOrder() {
+ return InitializerOrder.INTEGRATION_CONTROLLER_INITIALIZER;
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java
index 3c626f42553..146e200d067 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java
@@ -19,7 +19,6 @@
import io.gravitee.rest.api.service.common.UuidString;
import java.time.ZoneId;
import java.time.ZonedDateTime;
-import java.util.UUID;
import java.util.function.Supplier;
public class IntegrationFixture {
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/repository/IntegrationFixture.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/repository/IntegrationFixture.java
new file mode 100644
index 00000000000..161f3f0ed8d
--- /dev/null
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/repository/IntegrationFixture.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2015 The Gravitee team (http://gravitee.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package fixtures.repository;
+
+import io.gravitee.repository.management.model.Integration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Supplier;
+
+public class IntegrationFixture {
+
+ private IntegrationFixture() {}
+
+ public static final Supplier BASE = () ->
+ Integration
+ .builder()
+ .id("integration-id")
+ .name("An integration")
+ .description("A description")
+ .provider("amazon")
+ .environmentId("environment-id")
+ .createdAt(Date.from(Instant.parse("2020-02-03T20:22:02.00Z")))
+ .updatedAt(Date.from(Instant.parse("2020-02-04T20:22:02.00Z")));
+
+ public static Integration anIntegration() {
+ return BASE.get().build();
+ }
+}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java
index ff6d77b6423..96ccb29b5d3 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java
@@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
public class IntegrationCrudServiceInMemory implements IntegrationCrudService, InMemoryAlternative {
@@ -31,6 +32,11 @@ public Integration create(Integration integration) {
return integration;
}
+ @Override
+ public Optional findById(String id) {
+ return storage.stream().filter(item -> item.getId().equals(id)).findFirst();
+ }
+
@Override
public void initWith(List items) {
storage.clear();
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java
index 4f7abcc4c52..b8893006a93 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java
@@ -26,8 +26,12 @@
import io.gravitee.repository.exceptions.TechnicalException;
import io.gravitee.repository.management.api.IntegrationRepository;
import io.gravitee.rest.api.service.exceptions.TechnicalManagementException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.util.Optional;
import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
public class IntegrationCrudServiceImplTest {
@@ -42,32 +46,97 @@ void setUp() {
service = new IntegrationCrudServiceImpl(integrationRepository);
}
- @Test
- @SneakyThrows
- void should_create_integration() {
- //Given
- Integration integration = IntegrationFixture.anIntegration();
- when(integrationRepository.create(any())).thenAnswer(invocation -> invocation.getArgument(0));
+ @Nested
+ class Create {
- //When
- Integration createdIntegration = service.create(integration);
+ @Test
+ @SneakyThrows
+ void should_create_integration() {
+ //Given
+ Integration integration = IntegrationFixture.anIntegration();
+ when(integrationRepository.create(any())).thenAnswer(invocation -> invocation.getArgument(0));
- //Then
- assertThat(createdIntegration).isEqualTo(integration);
+ //When
+ Integration createdIntegration = service.create(integration);
+
+ //Then
+ assertThat(createdIntegration).isEqualTo(integration);
+ }
+
+ @Test
+ void should_throw_when_technical_exception_occurs() throws TechnicalException {
+ // Given
+ var integration = IntegrationFixture.anIntegration();
+ when(integrationRepository.create(any())).thenThrow(TechnicalException.class);
+
+ // When
+ Throwable throwable = catchThrowable(() -> service.create(integration));
+
+ // Then
+ assertThat(throwable)
+ .isInstanceOf(TechnicalManagementException.class)
+ .hasMessage("Error when creating Integration: Test integration");
+ }
}
- @Test
- void should_throw_when_technical_exception_occurs() throws TechnicalException {
- // Given
- var integration = IntegrationFixture.anIntegration();
- when(integrationRepository.create(any())).thenThrow(TechnicalException.class);
+ @Nested
+ class FindById {
+
+ @Test
+ @SneakyThrows
+ void should_return_the_found_integration() {
+ //Given
+ when(integrationRepository.findById(any()))
+ .thenAnswer(invocation ->
+ Optional.of(fixtures.repository.IntegrationFixture.anIntegration().toBuilder().id(invocation.getArgument(0)).build())
+ );
+
+ //When
+ var result = service.findById("my-id");
+
+ //Then
+ assertThat(result)
+ .contains(
+ IntegrationFixture
+ .anIntegration()
+ .toBuilder()
+ .id("my-id")
+ .name("An integration")
+ .description("A description")
+ .provider("amazon")
+ .environmentId("environment-id")
+ .createdAt(Instant.parse("2020-02-03T20:22:02.00Z").atZone(ZoneId.systemDefault()))
+ .updatedAt(Instant.parse("2020-02-04T20:22:02.00Z").atZone(ZoneId.systemDefault()))
+ .build()
+ );
+ }
+
+ @Test
+ @SneakyThrows
+ void should_return_empty_when_not_found() {
+ //Given
+ when(integrationRepository.findById(any())).thenAnswer(invocation -> Optional.empty());
+
+ //When
+ var result = service.findById("my-id");
+
+ //Then
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ void should_throw_when_technical_exception_occurs() throws TechnicalException {
+ // Given
+ var integration = IntegrationFixture.anIntegration();
+ when(integrationRepository.findById(any())).thenThrow(TechnicalException.class);
- // When
- Throwable throwable = catchThrowable(() -> service.create(integration));
+ // When
+ Throwable throwable = catchThrowable(() -> service.findById("my-id"));
- // Then
- assertThat(throwable)
- .isInstanceOf(TechnicalManagementException.class)
- .hasMessage("Error when creating Integration: Test integration");
+ // Then
+ assertThat(throwable)
+ .isInstanceOf(TechnicalManagementException.class)
+ .hasMessage("An error occurs while trying to find the integration: my-id");
+ }
}
}
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/pom.xml b/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/pom.xml
index 2952e307e55..3582a8d5b71 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/pom.xml
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/pom.xml
@@ -60,6 +60,12 @@
${project.version}
+
+ io.gravitee.apim.rest.api
+ gravitee-apim-rest-api-integration-controller
+ ${project.version}
+
+
io.gravitee.apim.rest.api.management
gravitee-apim-rest-api-management-rest
diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/src/main/java/io/gravitee/rest/api/standalone/spring/StandaloneConfiguration.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/src/main/java/io/gravitee/rest/api/standalone/spring/StandaloneConfiguration.java
index 35c40c1e105..28e2191402e 100644
--- a/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/src/main/java/io/gravitee/rest/api/standalone/spring/StandaloneConfiguration.java
+++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-standalone/gravitee-apim-rest-api-standalone-container/src/main/java/io/gravitee/rest/api/standalone/spring/StandaloneConfiguration.java
@@ -15,6 +15,7 @@
*/
package io.gravitee.rest.api.standalone.spring;
+import io.gravitee.integration.controller.spring.IntegrationControllerConfiguration;
import io.gravitee.node.api.Node;
import io.gravitee.node.api.NodeMetadataResolver;
import io.gravitee.node.container.NodeFactory;
@@ -40,6 +41,7 @@
{
RestManagementConfiguration.class,
io.gravitee.rest.api.management.v2.rest.spring.RestManagementConfiguration.class,
+ IntegrationControllerConfiguration.class,
RestPortalConfiguration.class,
}
)
diff --git a/gravitee-apim-rest-api/pom.xml b/gravitee-apim-rest-api/pom.xml
index a166599c2be..cf9a438c682 100644
--- a/gravitee-apim-rest-api/pom.xml
+++ b/gravitee-apim-rest-api/pom.xml
@@ -39,6 +39,7 @@
gravitee-apim-rest-api-fetcher
gravitee-apim-rest-api-model
gravitee-apim-rest-api-idp
+ gravitee-apim-rest-api-integration-controller
gravitee-apim-rest-api-repository
gravitee-apim-rest-api-rest
gravitee-apim-rest-api-service
diff --git a/pom.xml b/pom.xml
index af5fadea93e..385d8f305d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,9 +62,11 @@
3.0.2
4.0.0
1.1.4
+ 1.0.0-alpha.7
3.1.0
1.4.0
3.5.0
+ 1.0.0-alpha.3
5.10.0
1.4.3
3.1.0