Write a contract for several providers - spring-boot

I have a client UI microservice that uses several other microservices so I would like to write the contract test for each providers.
I have tried to write the following code:
public class ClientUIContractProductsTest {
// Pact mock Provider
#Rule
public PactProviderRuleMk2 providerOrdersMicroservice = new PactProviderRuleMk2("microservice-orders", "localhost", 9002, this);
#Rule
public PactProviderRuleMk2 providerProductsMicroservice = new PactProviderRuleMk2("microservice-products", "localhost", 9005, this);
// Step (1)
#Pact(consumer = "microservice-clientui")
public RequestResponsePact createPactForProducts(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return builder
.given("test GET /orders")
.uponReceiving("GET REQUEST FOR ORDERS")
.path("/orders")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(LambdaDsl.newJsonArray((a) -> {
a.object((o) -> o
.numberType("id", 1)
.numberType("productId", 1)
.timestamp("dateOrder", "yyyy-MM-dd'T'HH:mm:ss.SSS+0000")
.numberType("quantity",1)
.booleanType("orderPayed", false)
);
}
).build())
.given("test GET /Products")
.uponReceiving("GET REQUEST FOR PRODUCTS")
.path("/Products")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(PactDslJsonArray.arrayEachLike()
.numberType("id", 0)
.stringType("title", "Candle working with fire")
.stringType("description", "Candle working like a bulb but without electricity")
.stringType("image","https://live.staticflickr.com/3408/3279558099_6dc30be4b6_b.jpg")
.numberType("price", 22)
.closeObject())
.toPact();
}
#Test
#PactVerification()
public void pactVerification() {
// when
ResponseEntity<String> responseOrders = new RestTemplate()
.getForEntity(providerOrdersMicroservice.getUrl() + "/orders", String.class);
// Step (4)
// then
assertThat(responseOrders.getStatusCode().value()).isEqualTo(200);
/*
* Pact verification for products micro-service
* */
// when
ResponseEntity<String> responseProducts = new RestTemplate()
.getForEntity(providerProductsMicroservice.getUrl() + "/Products", String.class);
// Step (4)
// then
assertThat(responseProducts.getStatusCode().value()).isEqualTo(200);
}
}
But I had an error when running this code. But when I run with only one #Rule
How can I implement the contract to mock multiple providers?

I have found the solution here: https://github.com/DiUS/pact-jvm/tree/master/pact-jvm-consumer-junit#requiring-a-test-with-multiple-providers
Here is the code:
package com.clientui;
import au.com.dius.pact.consumer.Pact;
import au.com.dius.pact.consumer.PactProviderRuleMk2;
import au.com.dius.pact.consumer.PactVerification;
import au.com.dius.pact.consumer.dsl.PactDslJsonArray;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.model.RequestResponsePact;
import io.pactfoundation.consumer.dsl.LambdaDsl;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
public class ClientUIContractProductsTest {
// Pact mock Provider
#Rule
public PactProviderRuleMk2 providerOrdersMicroservice = new PactProviderRuleMk2("microservice-orders",this);
#Rule
public PactProviderRuleMk2 providerProductsMicroservice = new PactProviderRuleMk2("microservice-products", this);
// Step (1)
#Pact(provider= "microservice-orders", consumer = "microservice-clientui")
public RequestResponsePact createPactForOrders(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return builder
.given("test GET /orders")
.uponReceiving("GET REQUEST FOR ORDERS")
.path("/orders")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(LambdaDsl.newJsonArray((a) -> {
a.object((o) -> o
.numberType("id", 1)
.numberType("productId", 1)
.timestamp("dateOrder", "yyyy-MM-dd'T'HH:mm:ss.SSS+0000")
.numberType("quantity",1)
.booleanType("orderPayed", false)
);
}
).build())
.toPact();
}
#Pact(provider= "microservice-products", consumer = "microservice-clientui")
public RequestResponsePact createPactForProducts(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return builder
.given("test GET /Products")
.uponReceiving("GET REQUEST FOR PRODUCTS")
.path("/Products")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(PactDslJsonArray.arrayEachLike()
.numberType("id", 0)
.stringType("title", "Candle working with fire")
.stringType("description", "Candle working like a bulb but without electricity")
.stringType("image","https://live.staticflickr.com/3408/3279558099_6dc30be4b6_b.jpg")
.numberType("price", 22)
.closeObject())
.toPact();
}
#Test
#PactVerification({"microservice-orders", "microservice-products"})
public void pactVerification() {
// when
ResponseEntity<String> responseOrders = new RestTemplate()
.getForEntity(providerOrdersMicroservice.getUrl() + "/orders", String.class);
// Step (4)
// then
assertThat(responseOrders.getStatusCode().value()).isEqualTo(200);
/*
* Pact verification for products micro-service
* */
// when
ResponseEntity<String> responseProducts = new RestTemplate()
.getForEntity(providerProductsMicroservice.getUrl() + "/Products", String.class);
// Step (4)
// then
assertThat(responseProducts.getStatusCode().value()).isEqualTo(200);
}
}

Related

spring boot drools ConstraintEvaluationException with multiple drl files

spring boot 2.x, kie-ci 7.59.0.Final
package com.collyer.rest.config;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
#Configuration
public class DroolsConfig {
private static final String RULES_PATH = "rule/";
#Bean
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
}
return kieFileSystem;
}
private Resource[] getRuleFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
}
#Bean
public KieContainer kieContainer() throws IOException {
final KieRepository kieRepository = getKieServices().getRepository();
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
}
private KieServices getKieServices() {
return KieServices.Factory.get();
}
}
I have one d.drl file under the src/main/resources/rule, it looks like:
package com.my.rest.service;
//set import and global
rule "groupA_A_0"
agenda-group "groupA"
activation-group "groupA_A"
when
$j : JSONObject(aSize == 1)
then
System.out.println("####A-0");
....
end
the code to fire is:
#Autowired
private KieContainer kieContainer;
public testA() {
KieSession kSession = kieContainer.newKieSession();
//...set global
JSONObject json = new JSONObject();
json.put("aSize", 1);
kSession.getAgenda().getAgendaGroup("groupA").setFocus();
kSession.insert(json);
kSession.fireAllRules();
}
it works fine.
However, if I add another a.drl whose is
package com.my.rest.service;
//set import and global
rule "groupB_A_0"
agenda-group "groupB"
activation-group "groupB_A"
when
$j : JSONObject(bSize == 1)
then
System.out.println("####A-0");
....
end
the corresponding code to fire is:
public testB() {
KieSession kSession = kieContainer.newKieSession();
//...set global
JSONObject json = new JSONObject();
json.put("bSize", 2);
kSession.getAgenda().getAgendaGroup("groupB").setFocus();
kSession.insert(json);
kSession.fireAllRules();
}
the error thrown when executing testB() which is used to fire rules of a.drl:
org.drools.mvel.ConstraintEvaluationException: Error evaluating constraint 'aSize == 1' in [Rule "groupA_A_0" in rule/d.drl]
JSONObject is net.sf.json.JSONObject(like a Map), aSize is put into JSONObject when fire rules of d.drl while bSize is put when fire rules of a.drl.
i just want to fire rules of a.drl, why it said the error of d.drl?(and at this time, fire rules of d.drl is successed)
how to fix it?

OAuth2, Access /oauth2/token ressource behind a proxy

I need to consume an API securised by OAuth2 with WebClient. I have configure the OAuth2AuthorizedClientManager to manage the access token and refresh it when it need to be.
However I encounter some issue, java.net.UnknownHostException. There is a proxy between my Application and the OAuth2 token ressource and I do not know how to configure it.
What I have try :
Test it in an other environment without proxy and it's work. My OAuth2AuthorizedClientManager configuration is correct.
System.setProperty(), not a solution, I have several proxy to manage.
maybe I am misunderstanding some OAuth2 notions
Here some code:
application.properties
spring.security.oauth2.client.registration.client.client-id=clientId
spring.security.oauth2.client.registration.client.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.client.client-secret=clientSecret
spring.security.oauth2.client.provider.client.token-uri=URI/oauth2/token
WebClientConfig
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService clientService)
{
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, clientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
#Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("client");
return WebClient.builder()
.baseUrl("URI")
.clientConnector(getReactorClientHttpConnector(url))
.apply(oauth2Client.oauth2Configuration())
.build();
}
My test
#Autowired
WebClient webClient;
public void test() {
RequestHeadersSpec<?> request = webClient.get()
.uri("/heartbeats");
}
Error
org.springframework.security.oauth2.core.OAuth2AuthorizationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: I/O error on POST request for "URI/oauth2/token": URI; nested exception is java.net.UnknownHostException: URI
My question is, How to configure a proxy for the OAuth2AuthorizedClientManager ?
Please feel free to ask for clarification.
Any help would be appreciated. Thanks
We had some similar problem in the past and solved it by following configuration.
#Configuration
public class AuthConfiguration {
#Bean
public JwtDecoderFactory<ClientRegistration> jwtDecoderFactory() {
return new CustomOidcIdTokenDecoderFactory(jwksRestTemplate());
}
#Bean
public DefaultAuthorizationCodeTokenResponseClient oAuth2AccessTokenResponseClient() {
var defaultAuthorizationCodeTokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
defaultAuthorizationCodeTokenResponseClient.setRestOperations(tokenRestTemplate());
return defaultAuthorizationCodeTokenResponseClient;
}
#Bean
public RestTemplate jwksRestTemplate() {
return new RestTemplate(requestFactory());
}
#Bean
public RestTemplate tokenRestTemplate() {
// Copied from constructor of DefaultAuthorizationCodeTokenResponseClient
var restTemplate = new RestTemplate(Arrays.asList(
new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter()));
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
restTemplate.setRequestFactory(requestFactory());
return restTemplate;
}
private ClientHttpRequestFactory requestFactory() {
var requestFactory = new SimpleClientHttpRequestFactory();
var proxy = new Proxy(Type.HTTP, new InetSocketAddress("my.host.com", 8080));
requestFactory.setProxy(proxy);
return requestFactory;
}
}
Maybe this helps. Also the following class needs to be added because it is package private in Spring ;)
package org.springframework.security.oauth2.client.oidc.authentication;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.oauth2.client.oidc.authentication.DefaultOidcIdTokenValidatorFactory;
import org.springframework.security.oauth2.client.oidc.authentication.OidcIdTokenDecoderFactory;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.converter.ClaimTypeConverter;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithm;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
import java.util.function.Function;
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri;
/**
* extension for {#link OidcIdTokenDecoderFactory} to mock the JWKS request
*/
public class CustomOidcIdTokenDecoderFactory implements JwtDecoderFactory<ClientRegistration> {
private static final String MISSING_SIGNATURE_VERIFIER_ERROR_CODE = "missing_signature_verifier";
private static final Converter<Map<String, Object>, Map<String, Object>> DEFAULT_CLAIM_TYPE_CONVERTER =
new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters());
private Function<ClientRegistration, JwsAlgorithm> jwsAlgorithmResolver = clientRegistration -> SignatureAlgorithm.RS256;
private Function<ClientRegistration, OAuth2TokenValidator<Jwt>> jwtValidatorFactory = new DefaultOidcIdTokenValidatorFactory();
private Function<ClientRegistration, Converter<Map<String, Object>, Map<String, Object>>> claimTypeConverterFactory =
clientRegistration -> DEFAULT_CLAIM_TYPE_CONVERTER;
private final RestTemplate restTemplate;
public CustomOidcIdTokenDecoderFactory(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
#Override
public JwtDecoder createDecoder(ClientRegistration clientRegistration) {
NimbusJwtDecoder jwtDecoder = buildDecoder(clientRegistration);
jwtDecoder.setJwtValidator(this.jwtValidatorFactory.apply(clientRegistration));
Converter<Map<String, Object>, Map<String, Object>> claimTypeConverter =
this.claimTypeConverterFactory.apply(clientRegistration);
if (claimTypeConverter != null) {
jwtDecoder.setClaimSetConverter(claimTypeConverter);
}
return jwtDecoder;
}
private NimbusJwtDecoder buildDecoder(ClientRegistration clientRegistration) {
JwsAlgorithm jwsAlgorithm = this.jwsAlgorithmResolver.apply(clientRegistration);
String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri();
if (!StringUtils.hasText(jwkSetUri)) {
OAuth2Error oauth2Error = new OAuth2Error(
MISSING_SIGNATURE_VERIFIER_ERROR_CODE,
"Failed to find a Signature Verifier for Client Registration: '" +
clientRegistration.getRegistrationId() +
"'. Check to ensure you have configured the JwkSet URI.",
null
);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
return withJwkSetUri(jwkSetUri).jwsAlgorithm((SignatureAlgorithm) jwsAlgorithm).restOperations(restTemplate).build();
}
}

Sync S3 Bucket and listen for changes

I've got an AWS S3 bucket, where I place on a weekly basis a new ZIP file.
I want to add a functionality to my existing Web Service, written with Spring Boot: synchronize the bucket locally and watch for changes.
For the time being, synchronization works well: whenever a new file is added to the bucket, it gets downloaded locally. However, I don't know to listen for file updates, this is, a method that fires when a new file is downloaded locally. Can it be done?
This is the piece of code I've:
# --------
# | AWS S3 |
# --------
s3.credentials-access-key=***
s3.credentials-secret-key=****
s3.bucket = my-bucket
s3.remote-dir = zips
s3.local-dir = D:/s3-bucket/
#Log4j2
#Configuration
public class S3Config {
public static final String OUT_CHANNEL_NAME = "s3filesChannel";
#Value("${s3.credentials-access-key}") private String accessKey;
#Value("${s3.credentials-secret-key}") private String secretKey;
#Value("${s3.remote-dir}") private String remoteDir;
#Value("${s3.bucket}") private String s3bucket;
#Value("${s3.local-dir}") private String localDir;
/*
* AWS S3
*/
#Bean
public AmazonS3 getAmazonS3(
){
BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, secretKey);
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withRegion(Regions.EU_WEST_1)
.withCredentials(new AWSStaticCredentialsProvider(creds))
.build();
return s3client;
}
#Bean
public S3SessionFactory s3SessionFactory(AmazonS3 pAmazonS3) {
return new S3SessionFactory(pAmazonS3);
}
#Bean
public S3InboundFileSynchronizer s3InboundFileSynchronizer(S3SessionFactory pS3SessionFactory) {
S3InboundFileSynchronizer sync = new S3InboundFileSynchronizer(pS3SessionFactory);
sync.setPreserveTimestamp(true);
sync.setDeleteRemoteFiles(false);
String fullRemotePath = s3bucket.concat("/").concat(remoteDir);
sync.setRemoteDirectory(fullRemotePath);
sync.setFilter(new S3RegexPatternFileListFilter(".*\\.zip$"));
return sync;
}
#Bean
#InboundChannelAdapter(value = OUT_CHANNEL_NAME, poller = #Poller(fixedDelay = "30"))
public S3InboundFileSynchronizingMessageSource s3InboundFileSynchronizingMessageSource(
S3InboundFileSynchronizer pS3InboundFileSynchronizer
) {
S3InboundFileSynchronizingMessageSource messageSource = new S3InboundFileSynchronizingMessageSource(pS3InboundFileSynchronizer);
messageSource.setAutoCreateLocalDirectory(true);
messageSource.setLocalDirectory(new File(localDir));
messageSource.setLocalFilter(new AcceptOnceFileListFilter<File>());
return messageSource;
}
#Bean("s3filesChannel")
public PollableChannel s3FilesChannel() {
return new QueueChannel();
}
#Bean
public IntegrationFlow fileReadingFlow(
S3InboundFileSynchronizingMessageSource pS3InboundFileSynchronizingMessageSource,
GtfsBizkaibus pGtfsBizkaibus,
#Qualifier("fileProcessor") MessageHandler pMessageHandler) {
return IntegrationFlows
.from(pS3InboundFileSynchronizingMessageSource, e -> e.poller(p -> p.fixedDelay(5, TimeUnit.SECONDS)))
.handle(pMessageHandler)
.get();
}
#Bean("fileProcessor")
public MessageHandler fileProcessor() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(localDir));
handler.setExpectReply(false); // end of pipeline, reply not needed
handler.setFileExistsMode(FileExistsMode.APPEND);
handler.setNewFileCallback((file, msg) -> {
log.debug("New file created... " + file.getAbsolutePath());
});
return handler;
}
You can use S3 Event Notifications and an SQS queue. Basically when an object is added to your bucket, S3 can publish an event to a registered SQS queue. You can then have your on-premise application long poll the queue for new events and process any events that are added.
See here for more information.
Actually, the S3InboundFileSynchronizingMessageSource does all the necessary work for you: when new file is added into a remote bucket, it is downloaded to local dir and produced as a payload in the message to be sent to the configured channel.
When remote file is modified, it is also downloaded to local dir.
Starting with version 5.0, the AbstractInboundFileSynchronizingMessageSource provides this option:
/**
* Switch the local {#link FileReadingMessageSource} to use its internal
* {#code FileReadingMessageSource.WatchServiceDirectoryScanner}.
* #param useWatchService the {#code boolean} flag to switch to
* {#code FileReadingMessageSource.WatchServiceDirectoryScanner} on {#code true}.
* #since 5.0
*/
public void setUseWatchService(boolean useWatchService) {
this.fileSource.setUseWatchService(useWatchService);
if (useWatchService) {
this.fileSource.setWatchEvents(
FileReadingMessageSource.WatchEventType.CREATE,
FileReadingMessageSource.WatchEventType.MODIFY,
FileReadingMessageSource.WatchEventType.DELETE);
}
}
If that makes some sense to you.
But yeah... with S3 to SQS notification it is also going to be a good solution. There is an SqsMessageDrivenChannelAdapter in Spring Integration AWS project.
Finally, as #Artem Bilian suggested, I've make use of #ServiceActivator annotation. Here it's the full example:
import java.io.File;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.aws.inbound.S3InboundFileSynchronizer;
import org.springframework.integration.aws.inbound.S3InboundFileSynchronizingMessageSource;
import org.springframework.integration.aws.support.S3SessionFactory;
import org.springframework.integration.aws.support.filters.S3RegexPatternFileListFilter;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.PollableChannel;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import lombok.extern.log4j.Log4j2;
#Log4j2
#Configuration
public class S3Config {
public static final String IN_CHANNEL_NAME = "s3filesChannel";
#Value("${s3.credentials-access-key}") private String accessKey;
#Value("${s3.credentials-secret-key}") private String secretKey;
#Value("${s3.remote-dir}") private String remoteDir;
#Value("${s3.bucket}") private String s3bucket;
#Value("${s3.local-dir}") private String localDir;
/*
* AWS S3
*/
#Bean
public AmazonS3 getAmazonS3(
){
BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, secretKey);
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withRegion(Regions.EU_WEST_1)
.withCredentials(new AWSStaticCredentialsProvider(creds))
.build();
return s3client;
}
#Bean
public S3SessionFactory s3SessionFactory(AmazonS3 pAmazonS3) {
return new S3SessionFactory(pAmazonS3);
}
#Bean
public S3InboundFileSynchronizer s3InboundFileSynchronizer(S3SessionFactory pS3SessionFactory) {
S3InboundFileSynchronizer sync = new S3InboundFileSynchronizer(pS3SessionFactory);
sync.setPreserveTimestamp(true);
sync.setDeleteRemoteFiles(false);
String fullRemotePath = s3bucket.concat("/").concat(remoteDir);
sync.setRemoteDirectory(fullRemotePath);
sync.setFilter(new S3RegexPatternFileListFilter(".*\\.zip$"));
return sync;
}
#Bean
#InboundChannelAdapter(value = IN_CHANNEL_NAME, poller = #Poller(fixedDelay = "30"))
public S3InboundFileSynchronizingMessageSource s3InboundFileSynchronizingMessageSource(
S3InboundFileSynchronizer pS3InboundFileSynchronizer
) {
S3InboundFileSynchronizingMessageSource messageSource = new S3InboundFileSynchronizingMessageSource(pS3InboundFileSynchronizer);
messageSource.setAutoCreateLocalDirectory(true);
messageSource.setLocalDirectory(new File(localDir));
messageSource.setUseWatchService(true);
return messageSource;
}
#Bean("s3filesChannel")
public PollableChannel s3FilesChannel() {
return new QueueChannel();
}
#Bean
public IntegrationFlow fileReadingFlow(
S3InboundFileSynchronizingMessageSource pS3InboundFileSynchronizingMessageSource,
#Qualifier("fileProcessor") MessageHandler pMessageHandler) {
return IntegrationFlows
.from(pS3InboundFileSynchronizingMessageSource, e -> e.poller(p -> p.fixedDelay(5, TimeUnit.SECONDS)))
.handle(pMessageHandler)
.get();
}
#Bean("fileProcessor")
public MessageHandler fileProcessor() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(localDir));
handler.setExpectReply(false); // end of pipeline, reply not needed
handler.setFileExistsMode(FileExistsMode.REPLACE);
return handler;
}
#ServiceActivator(inputChannel = IN_CHANNEL_NAME, poller = #Poller(fixedDelay = "30"))
public void asada(Message<?> message) {
// TODO
log.debug("<< New message!");
}
}
Note that I've replaced OUT_CHANNEL_NAME by IN_CHANNEL_NAME.
PS: I'm almost new to Spring Integration, so I'm still learning its concepts.

How to access 2 Elasticsearch Instance through RestHighLevelClient in SpringBoot

I trying to access 2 Elasticsearch Server instance through HighLevelRestClient but I couldn't through this array object
HttpHost[] httpHost = new HttpHost(hostName[i...], Integer.parseInt(hostName[i..]), "http");
In hostname i have 2 values in the restHighLevelClient = new RestHighLevelClient( RestClient.builder(httpHost));
I'm also unable to access through second array instance.
Can I have 2 configuration Class if such way a how to create 2 instance of HighLevelRestClient
Or is it any possible way through 2 bean instance if such a way how it is possible
Since we need to have 2 different restHighLevelClient instance.
Kindly let me know in case of more information needed.
Code
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class AppElasticSearchConfiguration extends AbstractFactoryBean<RestHighLevelClient> {
private static final Logger LOG = LoggerFactory.getLogger(AppElasticSearchConfiguration.class);
#Value("${application.elasticsearch.host}")
private String hostName[];
private RestHighLevelClient restHighLevelClient;
#Override
public void destroy() {
try {
if (restHighLevelClient != null) {
restHighLevelClient.close();
}
} catch (final Exception e) {
LOG.error("Error closing ElasticSearch client: ", e);
}
}
#Override
public Class<RestHighLevelClient> getObjectType() {
return RestHighLevelClient.class;
}
#Override
public boolean isSingleton() {
return false;
}
#Override
public RestHighLevelClient createInstance() {
return buildClient();
}
private RestHighLevelClient buildClient() {
try {
HttpHost[] httpHost = null;
if(hostName!=null) {
httpHost = new HttpHost[hostName.length];
for (int i = 0; i < httpHost.length; i++) {
httpHost[i] = new HttpHost(hostName[i].split(":")[0],
Integer.parseInt(hostName[i].split(":")[1]), "http");
}
}
restHighLevelClient = new RestHighLevelClient( RestClient.builder(httpHost));
} catch (Exception e) {
LOG.error(e.getMessage());
}
return restHighLevelClient;
}
//public RestHighLevelClient getAppRestHighLevelClient() { return restHighLevelClient; }
}
Hi Just pass the secondary instance in the constructor of HttpHost.
#Bean(destroyMethod = "close")
public RestHighLevelClient buildClient() {
RestClientBuilder builder = RestClient.builder(new HttpHost(hostPrimary, Integer.valueOf(portPrimary), "http"),
new HttpHost(hostSecondary, Integer.valueOf(portSecondary), "http"));
RestHighLevelClient client = new RestHighLevelClient(builder);
LOG.info("RestHighLevelClient has been created with:{}", client);
return client;
}

How To Use Spring RESTTemplate To Post Data to a Web Service

I have written a jersey client code to call a webservice.And it is working fine. Now insteade of jersey i have to use the Spring rest template to call the webservice . So please help me in converting the jersey code to spring 4.0.
Here is my jersey code.
ServiceClient.java
package com.api.Client;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.tcs.DataShare.dao.ConfigureLogDao;
import com.tcs.ngps.sip.modeler.utils.ProductConfiguration;
public class ServiceClient {
static final Logger LOGGER = LoggerFactory
.getLogger(ServiceClient.class);
private WebResource service;
private ClientResponse response;
private String serviceName;
private String vmAddress;
private String portNumber;
private String WAR_FILE_NAME;
public ServiceClient(String localhost, String port,
String serviceName) {
this.vmAddress = localhost;
this.portNumber = port;
this.serviceName = serviceName;
System.out.println("vm address:" + vmAddress + "port:" + portNumber);
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WAR_FILE_NAME = ProductConfiguration
.getStringValueForProductProperty("DATASHARE_SERVER_WAR_FILE_NAME");
service = client.resource(UriBuilder.fromUri(
"http://" + vmAddress + ":" + portNumber + "/" + WAR_FILE_NAME)
.build());
LOGGER.debug("WAR_FILE_NAME in the client program"+WAR_FILE_NAME);
System.out.println("service is" + service);
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getVmAddress() {
return vmAddress;
}
public void setVmAddress(String vmAddress) {
this.vmAddress = vmAddress;
}
public String getPortNumber() {
return portNumber;
}
public void setPortNumber(String portNumber) {
this.portNumber = portNumber;
}
public InputStream zipFolder(String folderToBeZipped,String transactionId) {
LOGGER.debug("ServiceClient :: zipFolder() : Calling zipFolder Service -> folderToBeZipped: "
+ folderToBeZipped);
String header = getServiceName();
response = service.path("rest").path("DataShareService")
.path("zipFolder")
.type(MediaType.APPLICATION_JSON).header("header", header)
.post(ClientResponse.class, folderToBeZipped);
LOGGER.debug("INSIDE THE ZIP METHOD FOR CHECKING ZIP METHOD");
InputStream inputStream = response.getEntityInputStream();
LOGGER.debug("DataShareServiceClient :: zipFolder() : Calling zipFolderWithSubsequestFolder Service done");
return inputStream;
}
}
You can find it out with a simple search.
According to this tutorial from spring you can do it like this:
// Set the Content-Type header
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(new MediaType("application","json"));
HttpEntity<String> requestEntity = new HttpEntity<String>(folderToBeZipped, requestHeaders);
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();
// Add the Jackson and String message converters
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
// Make the HTTP POST request, marshaling the request to JSON, and the response to a String
ResponseEntity<InputStream> responseEntity = restTemplate.exchange(your_url, HttpMethod.POST, requestEntity, InputStream.class);
String result = responseEntity.getBody();
hope this helps.

Resources