From 2e4e7c26e656e6a451a510f79a7e7473de294d63 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Wed, 4 Mar 2020 14:15:40 +0100 Subject: [PATCH] feat(server): autodiscovery circuit breaker call (#8022) * Added circuit breaker instead of plain REST call to meta connection properties * Refactored common-model to add dynamic metadata modeling * Refactored MetadataCommand to be used as abstract base for MetadataCommandAction and MetadataConnectionPropertiesCommand * Refactored unit test to use DynamicConnectionPropertiesMetadata instead of raw Response * Removed useless pom dependencies Closes ENTESB-12498 --- .../connection/ConfigurationProperty.java | 2 +- .../connection/DynamicActionMetadata.java | 18 +-- .../DynamicConnectionPropertiesMetadata.java | 36 +++++ .../connection/WithDynamicProperties.java | 42 ++++++ app/server/endpoint/pom.xml | 10 -- .../connection/ConnectionActionHandler.java | 8 +- .../handler/connection/ConnectorHandler.java | 62 ++++---- .../ConnectorPropertiesHandler.java | 30 ++-- .../handler/connection/MetadataCommand.java | 40 ++---- .../connection/MetadataCommandAction.java | 46 ++++++ .../MetadataConnectionPropertiesCommand.java | 44 ++++++ .../ConnectionActionHandlerTest.java | 4 +- .../connection/ConnectorHandlerTest.java | 132 ++++++------------ .../ConnectorPropertiesHandlerTest.java | 52 +++++-- 14 files changed, 313 insertions(+), 213 deletions(-) create mode 100644 app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicConnectionPropertiesMetadata.java create mode 100644 app/common/model/src/main/java/io/syndesis/common/model/connection/WithDynamicProperties.java create mode 100644 app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommandAction.java create mode 100644 app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataConnectionPropertiesCommand.java diff --git a/app/common/model/src/main/java/io/syndesis/common/model/connection/ConfigurationProperty.java b/app/common/model/src/main/java/io/syndesis/common/model/connection/ConfigurationProperty.java index c4db0e2d25e..362f5217fa8 100644 --- a/app/common/model/src/main/java/io/syndesis/common/model/connection/ConfigurationProperty.java +++ b/app/common/model/src/main/java/io/syndesis/common/model/connection/ConfigurationProperty.java @@ -21,7 +21,7 @@ import io.syndesis.common.model.Ordered; import io.syndesis.common.model.WithTags; -import io.syndesis.common.model.connection.DynamicActionMetadata.ActionPropertySuggestion; +import io.syndesis.common.model.connection.WithDynamicProperties.ActionPropertySuggestion; import org.immutables.value.Value; diff --git a/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicActionMetadata.java b/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicActionMetadata.java index 89389b27d51..6597d0bf6dd 100644 --- a/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicActionMetadata.java +++ b/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicActionMetadata.java @@ -24,29 +24,15 @@ @Value.Immutable @JsonDeserialize(builder = DynamicActionMetadata.Builder.class) -public interface DynamicActionMetadata { +public interface DynamicActionMetadata extends WithDynamicProperties { DynamicActionMetadata NOTHING = new DynamicActionMetadata.Builder().build(); - @Value.Immutable - @JsonDeserialize(builder = ActionPropertySuggestion.Builder.class) - interface ActionPropertySuggestion { - - final class Builder extends ImmutableActionPropertySuggestion.Builder { - public static ActionPropertySuggestion of(final String value, final String displayValue) { - return new ActionPropertySuggestion.Builder().value(value).displayValue(displayValue).build(); - } - } - - String displayValue(); - - String value(); - } - final class Builder extends ImmutableDynamicActionMetadata.Builder { // make ImmutableDynamicActionMetadata.Builder accessible } + @Override Map> properties(); DataShape inputShape(); diff --git a/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicConnectionPropertiesMetadata.java b/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicConnectionPropertiesMetadata.java new file mode 100644 index 00000000000..91ed1ddc380 --- /dev/null +++ b/app/common/model/src/main/java/io/syndesis/common/model/connection/DynamicConnectionPropertiesMetadata.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * 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.syndesis.common.model.connection; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.immutables.value.Value; + +@Value.Immutable +@JsonDeserialize(builder = DynamicConnectionPropertiesMetadata.Builder.class) +public interface DynamicConnectionPropertiesMetadata extends WithDynamicProperties { + + DynamicConnectionPropertiesMetadata NOTHING = new DynamicConnectionPropertiesMetadata.Builder().build(); + + final class Builder extends ImmutableDynamicConnectionPropertiesMetadata.Builder { + // make ImmutableDynamicConnectionPropertiesMetadata.Builder accessible + } + + @Override + Map> properties(); +} diff --git a/app/common/model/src/main/java/io/syndesis/common/model/connection/WithDynamicProperties.java b/app/common/model/src/main/java/io/syndesis/common/model/connection/WithDynamicProperties.java new file mode 100644 index 00000000000..160357e63ff --- /dev/null +++ b/app/common/model/src/main/java/io/syndesis/common/model/connection/WithDynamicProperties.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * 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.syndesis.common.model.connection; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.immutables.value.Value; + +public interface WithDynamicProperties { + + @Value.Immutable + @JsonDeserialize(builder = ActionPropertySuggestion.Builder.class) + interface ActionPropertySuggestion { + + final class Builder extends ImmutableActionPropertySuggestion.Builder { + public static ActionPropertySuggestion of(final String value, final String displayValue) { + return new ActionPropertySuggestion.Builder().value(value).displayValue(displayValue).build(); + } + } + + String displayValue(); + + String value(); + } + + Map> properties(); +} diff --git a/app/server/endpoint/pom.xml b/app/server/endpoint/pom.xml index eea17b26ac5..70dfb69064f 100644 --- a/app/server/endpoint/pom.xml +++ b/app/server/endpoint/pom.xml @@ -198,11 +198,6 @@ jackson-module-jsonSchema - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - - org.jboss.spec.javax.ws.rs jboss-jaxrs-api_2.1_spec @@ -278,11 +273,6 @@ hystrix-core - - org.jboss.resteasy - resteasy-client - - org.hibernate.validator hibernate-validator diff --git a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandler.java b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandler.java index 83b3bf9a924..80ae7ce0d74 100644 --- a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandler.java +++ b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandler.java @@ -142,7 +142,7 @@ public Response enrichWithMetadata( // lastly put all connection properties parameters.putAll(encryptionComponent.decrypt(connection.getConfiguredProperties())); - final HystrixExecutable meta = createMetadataCommand(action, parameters); + final HystrixExecutable meta = createMetadataCommandAction(action, parameters); final DynamicActionMetadata dynamicActionMetadata = meta.execute(); final ConnectorDescriptor enrichedDescriptor = applyMetadataTo(generatedDescriptor, dynamicActionMetadata); @@ -157,9 +157,9 @@ public Response enrichWithMetadata( return Response.status(status).entity(metaResult).build(); } - protected HystrixExecutable createMetadataCommand(final ConnectorAction action, - final Map parameters) { - return new MetadataCommand(config, connectorId, action, parameters); + protected HystrixExecutable createMetadataCommandAction(final ConnectorAction action, + final Map parameters) { + return new MetadataCommandAction(config, connectorId, action, parameters); } private static DataShape adaptDataShape(final Optional maybeDataShape) { diff --git a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandler.java b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandler.java index 63f30608526..6fce940ee1b 100644 --- a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandler.java +++ b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandler.java @@ -25,8 +25,6 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status.Family; import javax.ws.rs.core.UriInfo; import java.io.BufferedInputStream; import java.io.IOException; @@ -35,16 +33,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import com.fasterxml.jackson.databind.JsonNode; -import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import io.syndesis.common.model.Kind; import io.syndesis.common.model.ListResult; import io.syndesis.common.model.action.ConnectorAction; @@ -52,6 +48,8 @@ import io.syndesis.common.model.connection.ConfigurationProperty; import io.syndesis.common.model.connection.Connection; import io.syndesis.common.model.connection.Connector; +import io.syndesis.common.model.connection.DynamicConnectionPropertiesMetadata; +import io.syndesis.common.model.connection.WithDynamicProperties; import io.syndesis.common.model.filter.FilterOptions; import io.syndesis.common.model.filter.Op; import io.syndesis.common.model.icon.Icon; @@ -129,7 +127,7 @@ public Connector get(final String id) { // Retrieve dynamic properties, if connector is dynamic if (connector.getTags().contains("dynamic")) { - connector = enrichWithDynamicProperties(connector); + connector = enrichConnectorWithDynamicProperties(connector); } final Optional connectorGroupId = connector.getConnectorGroupId(); @@ -149,48 +147,42 @@ public Connector get(final String id) { * @param connector * @return an enriched {@link Connector} */ - Connector enrichWithDynamicProperties(Connector connector) { + Connector enrichConnectorWithDynamicProperties(Connector connector) { final String connectorId = connector.getId().get(); final ConnectorPropertiesHandler propertiesHandler = properties(connectorId); - - final JsonNode jsonResponse; - try (Response response = propertiesHandler.enrichWithDynamicProperties(connectorId, null)) { - if (response.getStatusInfo().getFamily() != Family.SUCCESSFUL) { - return connector; - } - - jsonResponse = response.readEntity(JsonNode.class); + final Map dynamicProperties = enrichConfigurationPropertiesWithDynamicProperties( + connector.getProperties(), + propertiesHandler.dynamicConnectionProperties(connectorId) + ); + if (!dynamicProperties.isEmpty()) { + return connector.builder().properties(dynamicProperties).build(); } + return connector; + } - final Iterator> iterator = jsonResponse.path("properties").fields(); - final Map dynamicProperties = new HashMap<>(); - - while (iterator.hasNext()) { - Map.Entry next = iterator.next(); - String propertyName = next.getKey(); - JsonNode property = next.getValue(); + private static Map enrichConfigurationPropertiesWithDynamicProperties(Map inputProperties, + DynamicConnectionPropertiesMetadata dynamicConnectionProperties) { + Map dynamicProperties = new HashMap<>(); + for(Map.Entry> entry: dynamicConnectionProperties.properties().entrySet()){ + String propertyName = entry.getKey(); + List list = entry.getValue(); List values = new ArrayList<>(); - if (property.isArray()) { - for (final JsonNode value : property) { - ConfigurationProperty.PropertyValue val = new ConfigurationProperty.PropertyValue.Builder() - .label(value.get("displayValue").asText()) - .value(value.get("value").asText()) - .build(); - values.add(val); - } + + for (WithDynamicProperties.ActionPropertySuggestion suggestion : list) { + ConfigurationProperty.PropertyValue val = ConfigurationProperty.PropertyValue.Builder.from(suggestion); + values.add(val); } + if (!values.isEmpty()) { ConfigurationProperty configurationProperty = new ConfigurationProperty.Builder() - .createFrom(connector.getProperties().get(propertyName)) + .createFrom(inputProperties.get(propertyName)) .addEnum(values.toArray(new ConfigurationProperty.PropertyValue[0])) .build(); dynamicProperties.put(propertyName, configurationProperty); } } - if (!dynamicProperties.isEmpty()) { - return connector.builder().properties(dynamicProperties).build(); - } - return connector; + + return dynamicProperties; } @Path("/{connectorId}/actions") diff --git a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandler.java b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandler.java index af4ca47e4c2..be3321822fa 100644 --- a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandler.java +++ b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandler.java @@ -15,42 +15,34 @@ */ package io.syndesis.server.endpoint.v1.handler.connection; -import java.util.Map; - import javax.ws.rs.POST; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import java.util.Collections; +import com.netflix.hystrix.HystrixExecutable; import io.swagger.v3.oas.annotations.tags.Tag; +import io.syndesis.common.model.connection.DynamicConnectionPropertiesMetadata; import io.syndesis.server.verifier.MetadataConfigurationProperties; -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; - @Tag(name = "properties") public class ConnectorPropertiesHandler { - private final String metaPropertiesUrl; + private final MetadataConfigurationProperties config; public ConnectorPropertiesHandler(final MetadataConfigurationProperties config) { - metaPropertiesUrl = String.format("http://%s/api/v1/connectors/%%s/properties/meta", config.getService()); + this.config = config; } @POST @Produces(MediaType.APPLICATION_JSON) - public Response enrichWithDynamicProperties(@PathParam("id") final String connectorId, final Map props) { - // TODO replace properly with circuit breaker - String metadataUrl = String.format(metaPropertiesUrl, connectorId); - Client client = createClient(); - WebTarget target = client.target(metadataUrl); - - return target.request().post(Entity.entity(props, MediaType.APPLICATION_JSON_TYPE)); + public DynamicConnectionPropertiesMetadata dynamicConnectionProperties(@PathParam("id") final String connectorId) { + final HystrixExecutable meta = createMetadataConnectionPropertiesCommand(connectorId); + return meta.execute(); } - Client createClient() { - return new ResteasyClientBuilder().build(); + protected HystrixExecutable createMetadataConnectionPropertiesCommand(final String connectorId) { + return new MetadataConnectionPropertiesCommand(config, connectorId, Collections.emptyMap()); } + } diff --git a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommand.java b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommand.java index 1a2ad1cc34a..2c70618e1cc 100644 --- a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommand.java +++ b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommand.java @@ -15,8 +15,6 @@ */ package io.syndesis.server.endpoint.v1.handler.connection; -import java.util.Map; - import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientResponseFilter; @@ -25,53 +23,43 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status.Family; - -import io.syndesis.common.model.action.ConnectorAction; -import io.syndesis.common.model.connection.DynamicActionMetadata; -import io.syndesis.common.util.json.JsonUtils; -import io.syndesis.server.endpoint.v1.SyndesisRestException; -import io.syndesis.server.endpoint.v1.handler.exception.RestError; -import io.syndesis.server.verifier.MetadataConfigurationProperties; +import java.util.Map; import com.netflix.hystrix.HystrixCommand; import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.HystrixCommandProperties; import com.netflix.hystrix.HystrixThreadPoolProperties; +import io.syndesis.common.util.json.JsonUtils; +import io.syndesis.server.endpoint.v1.SyndesisRestException; +import io.syndesis.server.endpoint.v1.handler.exception.RestError; +import io.syndesis.server.verifier.MetadataConfigurationProperties; -class MetadataCommand extends HystrixCommand { - - private final String metadataUrl; +abstract class MetadataCommand extends HystrixCommand { private final Map parameters; + private final Class type; - MetadataCommand(final MetadataConfigurationProperties configuration, final String connectorId, final ConnectorAction action, - final Map parameters) { + MetadataCommand(final MetadataConfigurationProperties configuration, Class type, final Map parameters ) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("Meta"))// .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()// .withCoreSize(configuration.getThreads()))// .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()// .withExecutionTimeoutInMilliseconds(configuration.getTimeout()))); - this.parameters = parameters; - this.metadataUrl = String.format("http://%s/api/v1/connectors/%s/actions/%s", configuration.getService(), connectorId, action.getId().get()); + this.type = type; } @Override - protected DynamicActionMetadata getFallback() { - return DynamicActionMetadata.NOTHING; - } - - @Override - protected DynamicActionMetadata run() { + protected R run() { Client client = null; try { client = createClient(); - final WebTarget target = client.target(metadataUrl); + final WebTarget target = client.target(getMetadataURL()); final Entity entity = Entity.entity(parameters, MediaType.APPLICATION_JSON); - return target.request(MediaType.APPLICATION_JSON).post(entity, DynamicActionMetadata.class); + return target.request(MediaType.APPLICATION_JSON).post(entity, type); } finally { if (client != null) { client.close(); @@ -79,7 +67,9 @@ protected DynamicActionMetadata run() { } } - private static Client createClient() { + protected abstract String getMetadataURL(); + + protected Client createClient() { return ClientBuilder.newClient().register((ClientResponseFilter) (requestContext, responseContext) -> { if (responseContext.getStatusInfo().getFamily() == Family.SERVER_ERROR diff --git a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommandAction.java b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommandAction.java new file mode 100644 index 00000000000..eb133a76368 --- /dev/null +++ b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataCommandAction.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * 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.syndesis.server.endpoint.v1.handler.connection; + +import java.util.Map; + +import io.syndesis.common.model.action.ConnectorAction; +import io.syndesis.common.model.connection.DynamicActionMetadata; +import io.syndesis.server.verifier.MetadataConfigurationProperties; + +class MetadataCommandAction extends MetadataCommand { + + private final String metadataUrl; + + MetadataCommandAction(MetadataConfigurationProperties configuration, + final String connectorId, + final ConnectorAction action, + Map parameters) { + super(configuration, DynamicActionMetadata.class, parameters); + this.metadataUrl = String.format("http://%s/api/v1/connectors/%s/actions/%s", configuration.getService(), connectorId, action.getId().get()); + } + + @Override + protected DynamicActionMetadata getFallback() { + return DynamicActionMetadata.NOTHING; + } + + @Override + protected String getMetadataURL() { + return metadataUrl; + } + +} diff --git a/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataConnectionPropertiesCommand.java b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataConnectionPropertiesCommand.java new file mode 100644 index 00000000000..bd0fd0cc59e --- /dev/null +++ b/app/server/endpoint/src/main/java/io/syndesis/server/endpoint/v1/handler/connection/MetadataConnectionPropertiesCommand.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * 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.syndesis.server.endpoint.v1.handler.connection; + +import java.util.Map; + +import io.syndesis.common.model.connection.DynamicConnectionPropertiesMetadata; +import io.syndesis.server.verifier.MetadataConfigurationProperties; + +class MetadataConnectionPropertiesCommand extends MetadataCommand { + + private final String metadataUrl; + + MetadataConnectionPropertiesCommand(MetadataConfigurationProperties configuration, + final String connectorId, + Map parameters) { + super(configuration, DynamicConnectionPropertiesMetadata.class, parameters); + this.metadataUrl = String.format("http://%s/api/v1/connectors/%s/properties/meta", configuration.getService(), connectorId); + } + + @Override + protected DynamicConnectionPropertiesMetadata getFallback() { + return DynamicConnectionPropertiesMetadata.NOTHING; + } + + @Override + protected String getMetadataURL() { + return metadataUrl; + } + +} diff --git a/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandlerTest.java b/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandlerTest.java index 42eb3030f0d..cfd5403761d 100644 --- a/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandlerTest.java +++ b/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectionActionHandlerTest.java @@ -120,8 +120,8 @@ public ConnectionActionHandlerTest() { handler = new ConnectionActionHandler(connection, new MetadataConfigurationProperties(), new EncryptionComponent(null)) { @Override - protected HystrixExecutable createMetadataCommand(final ConnectorAction action, - final Map parameters) { + protected HystrixExecutable createMetadataCommandAction(final ConnectorAction action, + final Map parameters) { metadataCommandParameters = parameters; return metadataCommand; } diff --git a/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandlerTest.java b/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandlerTest.java index d2a8529d991..ffeb625cd01 100644 --- a/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandlerTest.java +++ b/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorHandlerTest.java @@ -15,60 +15,40 @@ */ package io.syndesis.server.endpoint.v1.handler.connection; -import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH; -import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayInputStream; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import javax.validation.constraints.NotNull; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; -import javax.validation.constraints.NotNull; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.StreamingOutput; - -import io.syndesis.server.verifier.MetadataConfigurationProperties; - -import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration; -import org.jboss.resteasy.client.jaxrs.internal.ClientResponse; -import org.jboss.resteasy.spi.ResteasyProviderFactory; -import org.junit.Test; -import org.springframework.context.ApplicationContext; - -import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; - -import io.syndesis.server.credential.Credentials; -import io.syndesis.server.dao.file.FileDataManager; -import io.syndesis.server.dao.file.IconDao; -import io.syndesis.server.dao.manager.DataManager; -import io.syndesis.server.dao.manager.EncryptionComponent; -import io.syndesis.server.inspector.Inspectors; import io.syndesis.common.model.ListResult; import io.syndesis.common.model.action.ConnectorAction; import io.syndesis.common.model.action.ConnectorDescriptor; import io.syndesis.common.model.connection.ConfigurationProperty; +import io.syndesis.common.model.connection.ConfigurationProperty.PropertyValue; import io.syndesis.common.model.connection.Connection; import io.syndesis.common.model.connection.Connector; -import io.syndesis.common.model.connection.ConfigurationProperty.PropertyValue; +import io.syndesis.common.model.connection.DynamicConnectionPropertiesMetadata; +import io.syndesis.common.model.connection.WithDynamicProperties; import io.syndesis.common.model.integration.Flow; import io.syndesis.common.model.integration.Integration; import io.syndesis.common.model.integration.Step; +import io.syndesis.server.credential.Credentials; +import io.syndesis.server.dao.file.FileDataManager; +import io.syndesis.server.dao.file.IconDao; +import io.syndesis.server.dao.manager.DataManager; +import io.syndesis.server.dao.manager.EncryptionComponent; import io.syndesis.server.endpoint.v1.state.ClientSideState; +import io.syndesis.server.inspector.Inspectors; +import io.syndesis.server.verifier.MetadataConfigurationProperties; import io.syndesis.server.verifier.Verifier; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -76,6 +56,15 @@ import okio.BufferedSink; import okio.BufferedSource; import okio.Okio; +import org.junit.Test; +import org.springframework.context.ApplicationContext; + +import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH; +import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class ConnectorHandlerTest { @@ -127,7 +116,7 @@ public void connectorIconShouldHaveCorrectContentType() throws IOException { final StreamingOutput so = (StreamingOutput) response.getEntity(); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); try (BufferedSink sink = Okio.buffer(Okio.sink(bos)); BufferedSource source = new Buffer(); - ImageInputStream iis = ImageIO.createImageInputStream(source.inputStream());) { + ImageInputStream iis = ImageIO.createImageInputStream(source.inputStream());) { so.write(sink.outputStream()); source.readAll(sink); final Iterator readers = ImageIO.getImageReaders(iis); @@ -191,15 +180,14 @@ public ConnectorPropertiesHandler properties(@NotNull String connectorId) { } }; - @SuppressWarnings("resource") - final Response metaResponse = responseWithEntity("{}"); + final DynamicConnectionPropertiesMetadata metaResponse = DynamicConnectionPropertiesMetadata.NOTHING; - when(connectorPropertiesHandler.enrichWithDynamicProperties("connectorId", null)).thenReturn(metaResponse); + when(connectorPropertiesHandler.dynamicConnectionProperties("connectorId")).thenReturn(metaResponse); final Connector connector = new Connector.Builder() .id("connectorId") .build(); - final Connector withDynamicProperties = connectorHandler.enrichWithDynamicProperties(connector); + final Connector withDynamicProperties = connectorHandler.enrichConnectorWithDynamicProperties(connector); final Connector expected = new Connector.Builder() .id("connectorId") @@ -221,16 +209,19 @@ public ConnectorPropertiesHandler properties(@NotNull String connectorId) { } }; - @SuppressWarnings("resource") - final Response metaResponse = responseWithEntity("{\"properties\":{\"property\":[{\"displayValue\":\"Value 1\",\"value\":\"value1\"},{\"displayValue\":\"Value 2\",\"value\":\"value2\"}]}}"); - - when(connectorPropertiesHandler.enrichWithDynamicProperties("connectorId", null)).thenReturn(metaResponse); + final DynamicConnectionPropertiesMetadata metaResponse = new DynamicConnectionPropertiesMetadata.Builder() + .putProperty("property", Arrays.asList( + new WithDynamicProperties.ActionPropertySuggestion.Builder().displayValue("Value 1").value("value1").build(), + new WithDynamicProperties.ActionPropertySuggestion.Builder().displayValue("Value 2").value("value2").build() + ) + ).build(); + when(connectorPropertiesHandler.dynamicConnectionProperties("connectorId")).thenReturn(metaResponse); final Connector connector = new Connector.Builder() .id("connectorId") .putProperty("property", new ConfigurationProperty.Builder().build()) .build(); - final Connector withDynamicProperties = connectorHandler.enrichWithDynamicProperties(connector); + final Connector withDynamicProperties = connectorHandler.enrichConnectorWithDynamicProperties(connector); final Connector expected = new Connector.Builder() .id("connectorId") @@ -242,37 +233,6 @@ public ConnectorPropertiesHandler properties(@NotNull String connectorId) { assertThat(withDynamicProperties).isEqualTo(expected); } - private static Response responseWithEntity(final String data) { - final ClientConfiguration configuration = new ClientConfiguration(new ResteasyProviderFactory().register(JacksonJsonProvider.class)); - final Response metaResponse = spy(new ClientResponse(configuration) { - @Override - protected InputStream getInputStream() { - return new ByteArrayInputStream(data.getBytes(StandardCharsets.US_ASCII)); - } - - @Override - protected void setInputStream(InputStream is) { - // nop - } - - @Override - public void releaseConnection() throws IOException { - // nop - } - - @Override - public void releaseConnection(boolean consumeInputStream) throws IOException { - // nop - } - - @Override - public MediaType getMediaType() { - return MediaType.APPLICATION_JSON_TYPE; - } - }); - return metaResponse; - } - @Test public void shouldNotFailToEnrichDynamicPropertiesWithErrorResponse() { final ConnectorPropertiesHandler connectorPropertiesHandler = mock(ConnectorPropertiesHandler.class); @@ -286,14 +246,14 @@ public ConnectorPropertiesHandler properties(@NotNull String connectorId) { } }; - @SuppressWarnings("resource") - final Response metaResponse = Response.serverError().build(); - when(connectorPropertiesHandler.enrichWithDynamicProperties("connectorId", null)).thenReturn(metaResponse); + //It would never provide an error, as in such case circuit breaker provide the fallback implementation + final DynamicConnectionPropertiesMetadata metaResponse = DynamicConnectionPropertiesMetadata.NOTHING; + when(connectorPropertiesHandler.dynamicConnectionProperties("connectorId")).thenReturn(metaResponse); final Connector connector = new Connector.Builder() .id("connectorId") .build(); - final Connector withDynamicProperties = connectorHandler.enrichWithDynamicProperties(connector); + final Connector withDynamicProperties = connectorHandler.enrichConnectorWithDynamicProperties(connector); final Connector expected = new Connector.Builder() .id("connectorId") @@ -320,10 +280,10 @@ private static Connector usedConnector(final Connector connector, final int usag } private static Integration newIntegration(List steps) { - return new Integration.Builder() - .id("test") - .name("test") - .addFlow(new Flow.Builder().steps(steps).build()) - .build(); + return new Integration.Builder() + .id("test") + .name("test") + .addFlow(new Flow.Builder().steps(steps).build()) + .build(); } } diff --git a/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandlerTest.java b/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandlerTest.java index 64f6bb9a71d..1aa7587e6c6 100644 --- a/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandlerTest.java +++ b/app/server/endpoint/src/test/java/io/syndesis/server/endpoint/v1/handler/connection/ConnectorPropertiesHandlerTest.java @@ -15,18 +15,21 @@ */ package io.syndesis.server.endpoint.v1.handler.connection; -import java.util.Collections; -import java.util.Map; - import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.netflix.hystrix.HystrixExecutable; +import io.syndesis.common.model.connection.DynamicConnectionPropertiesMetadata; +import io.syndesis.common.model.connection.WithDynamicProperties; import io.syndesis.server.verifier.MetadataConfigurationProperties; - import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -45,8 +48,13 @@ public void shouldSendRequestsToMeta() { final ConnectorPropertiesHandler handler = new ConnectorPropertiesHandler(config) { @Override - Client createClient() { - return client; + protected HystrixExecutable createMetadataConnectionPropertiesCommand(final String connectorId) { + return new MetadataConnectionPropertiesCommand(config, connectorId, Collections.emptyMap()){ + @Override + protected Client createClient() { + return client; + } + }; } }; @@ -55,16 +63,30 @@ Client createClient() { final WebTarget target = mock(WebTarget.class); when(client.target(url.capture())).thenReturn(target); final Invocation.Builder builder = mock(Invocation.Builder.class); - when(target.request()).thenReturn(builder); + when(target.request(MediaType.APPLICATION_JSON)).thenReturn(builder); final Map properties = Collections.emptyMap(); - @SuppressWarnings("resource") - final Response response = mock(Response.class); - when(builder.post(Entity.entity(properties, MediaType.APPLICATION_JSON_TYPE))).thenReturn(response); - - @SuppressWarnings("resource") - final Response received = handler.enrichWithDynamicProperties("connectorId", properties); + final Map> dynamicProperties = buildProperties(); + final DynamicConnectionPropertiesMetadata dynamicConnectionPropertiesMetadata = + new DynamicConnectionPropertiesMetadata.Builder() + .properties(dynamicProperties) + .build(); + when(builder.post(Entity.entity(properties, MediaType.APPLICATION_JSON_TYPE),DynamicConnectionPropertiesMetadata.class)) + .thenReturn(dynamicConnectionPropertiesMetadata); + final DynamicConnectionPropertiesMetadata received = handler.dynamicConnectionProperties("connectorId"); - assertThat(received).isSameAs(response); + assertThat(received).isSameAs(dynamicConnectionPropertiesMetadata); assertThat(url.getValue()).isEqualTo("http://syndesis-meta/api/v1/connectors/connectorId/properties/meta"); } + + private static Map> buildProperties() { + HashMap> properties = new HashMap<>(); + List values = new ArrayList<>(); + values.add(new WithDynamicProperties.ActionPropertySuggestion.Builder() + .value("valueTest") + .displayValue("displayValueTest") + .build() + ); + properties.put("someProperty", values); + return properties; + } }