Heloo every body , i am trying to connect through a feign client to an api , i am using the feign client in a jhipster gateway .. i already used the same code in a microservice and it worked fine this is the code i wrote :
#FeignClient( name = "berrycord" ,url = "https://dev1.digitalberry.fr/bcs-berrycord-direct/")
/**
* This interface is used to call berryscheduler APIs ,
* using netflix feign client
* #param body host to manage
*/
public interface TraceClientInterface {
#PostMapping("api/v1/records/")
public JSONObject sendReport(#RequestBody JSONObject report);
// #GetMapping(value="/jokes/count")
// public JSONObject sendReport();
}
#Component
public class UserFeignClientInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER = "Bearer";
#Override
public void apply(RequestTemplate template) {
System.out.println("test ========================" +template.request());
System.out.println("test ========================2" +template.toString());
System.out.println("test ========================3" +new String(template.body()));
SecurityUtils.getCurrentUserJWT()
.ifPresent(s -> template.header(AUTHORIZATION_HEADER,String.format("%s %s", BEARER, s)));
SecurityUtils.getCurrentUserLogin()
.ifPresent(user -> template.header("X-Forwarded-User", user));
SecurityUtils.getCurrentUserAuthorities()
.ifPresent(authorities -> template.header("X-Forwarded-Role", authorities));
}
}
/**
* This service communicates with berryCord to create a send report POST
* /api/v1/report/ endpoint, is called when creating or updating the host
* resource
*
* #param task
*/
public JSONObject sendReport(JSONObject report) {
log.debug("Request to create log report in berrycord ");
JSONObject rep = new JSONObject() ;
try {
log.info("=========== Request to create log report in berrycord 2 " , report);
rep = traceClientInterface.sendReport(report);
log.info("=========== Request to create log report in berrycord 3 " , report);
} catch (FeignException e) {
e.getStackTrace();
}
return rep;
}
feign:
hystrix:
enabled: false
client:
url:
berryCordUrl: https://dev1.digitalberry.fr/bcs-berrycord-direct/
But the connexion between the two is never done and i can't see results of the called API ..
Who can tell me please what i did wrong .. and thanks :) :)
You should have a #Configuration as following and add #EnableFeignClients to your Application.java
#Configuration
public class FooConfiguration {
#Bean
public UserFeignClientInterceptor userFeignClientInterceptor() {
return new UserFeignClientInterceptor();
}
}
Related
I use Retrofit2 to make REST API requests. I have my dummy server (that runs with spring boot) on my machine:
#RestController
class SecureServiceController {
private int counter = 1;
#RequestMapping(value = "/nnrf-nfm/v1/nf-instances/bee75393-2ac3-4e60-9503-854e733309d4", method = RequestMethod.PUT)
public ResponseEntity<NFProfile> nNrfNfManagementNfRegister() {
System.out.println(counter++ + ". Got NrfClient register request. " + new Date());
NFProfile nfProfile = new NFProfile();
nfProfile.setHeartBeatTimer(2);
ResponseEntity<NFProfile> responseEntity = ResponseEntity.status(201).body(nfProfile);
return responseEntity;
}
}
When client make request from the same machine it works. But when client make request from remote machine I have error response:
Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://myhostname:8443/nnrf-nfm/v1/nf-instances/bee75393-2ac3-4e60-9503-854e733309d4}
Response error body: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>Error</title></head><body><h1>Error</h1></body></html>
I've read that such error means that client don't have the rights to access and need to add access token. But my server does not ask any access token (at least explicitly) and it should not ask it.
How to solve this problem?
My apiClient:
public class ApiClient {
private Map<String, Interceptor> apiAuthorizations;
private Builder okBuilder;
private retrofit2.Retrofit.Builder adapterBuilder;
private JSON json;
//a lot setters and getters
public <S> S createService(Class<S> serviceClass) {
return this.adapterBuilder.client(this.okBuilder.build()).build().create(serviceClass);
}
public void configureFromOkclient(OkHttpClient okClient) {
this.okBuilder = okClient.newBuilder();
this.addAuthsToOkBuilder(this.okBuilder);
}
}
my interface:
public interface NfInstanceIdDocumentApi {
#Headers({"Content-Type:application/json"})
#PUT("nf-instances/{nfInstanceID}")
Call<NFProfile> registerNFInstance(#Body NFProfile body, #Path("nfInstanceID") UUID nfInstanceID, #Header("Content-Encoding") String contentEncoding, #Header("Accept-Encoding") String acceptEncoding);
}
How I do call:
OkHttpClient okHttpClient= ClientFactory.createClient();
ApiClient client = new ApiClient();
client.configureFromOkclient(okHttpClient);
NFProfile body = getNfProfile();
String baseUri = getBaseUri();
UUID uuid = getUUID();
//create call
client.getAdapterBuilder().baseUrl(baseUri);
NfInstanceIdDocumentApi service = client.createService(NfInstanceIdDocumentApi.class);
Call<NFProfile> call = service.registerNFInstance(body, uuid, null, null);
//make call
Response<NFProfile> response = call.execute();
UPD
I found the problem. Server was running on Windows machine and firewall blocked incoming requests.
A SOAP Web-service, which accepts request in following format -
<?xml version = "1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
xmlns:ns="http://...." xmlns:ns1="http://...." xmlns:ns2="http://...."
xmlns:ns3="http://....">
<SOAP-ENV:Header>
<ns:EMContext>
<messageId>1</messageId>
<refToMessageId>ABC123</refToMessageId>
<session>
<sessionId>3</sessionId>
<sessionSequenceNumber>2021-02-24T00:00:00.000+5:00</sessionSequenceNumber>
</session>
<invokerRef>CRS</invokerRef>
</ns:EMContext>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:getEmployee>
<ns:empId>111</ns:empId>
</ns1:getEmployee>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
When trying to make a SOAP request to it using JAXB2, it is giving org.springframework.ws.soap.client.SoapFaultClientException: EMContext Header is missing
I am using
pring-boot-starter
spring-boot-starter-web-services
org.jvnet.jaxb2.maven2 : maven-jaxb2-plugin : 0.14.0
and
Client -
public class MyClient extends WebServiceGatewaySupport {
public GetEmployeeResponse getEmployee(String url, Object request){
GetEmployeeResponse res = (GetEmployeeResponse) getWebServiceTemplate().marshalSendAndReceive(url, request);
return res;
}
}
Configuration -
#Configuration
public class EmpConfig {
#Bean
public Jaxb2Marshaller marshaller(){
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath("com.crsardar.java.soap.client.request");
return jaxb2Marshaller;
}
#Bean
public MyClient getClient(Jaxb2Marshaller jaxb2Marshaller){
MyClient myClient = new MyClient();
myClient.setDefaultUri("http://localhost:8080/ws");
myClient.setMarshaller(jaxb2Marshaller);
myClient.setUnmarshaller(jaxb2Marshaller);
return myClient;
}
}
App -
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#Bean
CommandLineRunner lookup(MyClient myClient){
return args -> {
GetEmployeeRequest getEmployeeRequest = new GetEmployeeRequest();
getEmployeeRequest.setId(1);
GetEmployeeResponse employee = myClient.getEmployee("http://localhost:8080/ws", getEmployeeRequest);
System.out.println("Response = " + employee.getEmployeeDetails().getName());
};
}
}
How can I add EMContext Header to the SOAP request?
The server is complaining because your Web Service client is not sending the EMContext SOAP header in your SOAP message.
Unfortunately, currently Spring Web Services lack of support for including SOAP headers in a similar way as the SOAP body information is processed using JAXB, for example.
As a workaround, you can use WebServiceMessageCallback. From the docs:
To accommodate the setting of SOAP headers and other settings on the message, the WebServiceMessageCallback interface gives you access to the message after it has been created, but before it is sent.
In your case, you can use something like:
public class MyClient extends WebServiceGatewaySupport {
public GetEmployeeResponse getEmployee(String url, Object request){
// Obtain the required information
String messageId = "1";
String refToMessageId = "ABC123";
String sessionId = "3";
String sessionSequenceNumber = "2021-02-24T00:00:00.000+5:00";
String invokerRef = "CRS";
GetEmployeeResponse res = (GetEmployeeResponse) this.getWebServiceTemplate().marshalSendAndReceive(url, request, new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
// Include the SOAP header content for EMContext
try {
SoapMessage soapMessage = (SoapMessage)message;
SoapHeader header = soapMessage.getSoapHeader();
StringSource headerSource = new StringSource(
"<EMContext xmlns:ns=\"http://....\">" +
"<messageId>" + messageId + "</messageId>" +
"<refToMessageId>" + refToMessageId + "</refToMessageId>" +
"<session>" +
"<sessionId>" + sessionId + "</sessionId>" +
"<sessionSequenceNumber>" + sessionSequenceNumber + "</sessionSequenceNumber>" +
"</session>" +
"<invokerRef>" + invokerRef + "</invokerRef>" +
"</EMContext>"
);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(headerSource, header.getResult());
} catch (Exception e) {
// handle the exception as appropriate
e.printStackTrace();
}
}
});
return res;
}
}
Similar questions have been posted in SO. Consider for instance review this or this other.
I am trying to create a scheduler that sends a get request to a web service and gets the count of the items we need. then divide the Total by per_page then send any number of requests needed but requests are Async.
my code is working perfectly fine in my test class but in the main Application im getting two error based on the JDK version
this is my API service :
public interface RestService {
#Async
CompletableFuture<UpcomingEventsResponse> getUpcomingEvents(int page,String day, String token);
UpcomingEventsResponse getUpcomingEvents(String day,String token);
}
my RestService Impl:
#Service
#RequiredArgsConstructor
#Slf4j
public class RestServiceImpl implements RestService {
public static final String UPCOMING_EVENTS_URL = "HTTP://localhost/test";
private final RestTemplate restTemplate;
#Override
public CompletableFuture<UpcomingEventsResponse> getUpcomingEvents(int page,String day, String token) {
String url = createUrl(UPCOMING_EVENTS_URL,createQuery("day",day),createQuery("page", page), createQuery("token", token));
return makeCallAsync(url,HttpMethod.GET,null,UpcomingEventsResponse.class);
}
#Override
public UpcomingEventsResponse getUpcomingEvents(String day,String token) {
String url = createUrl(UPCOMING_EVENTS_URL,createQuery("day",day), createQuery("page", 1), createQuery("token", token));
return makeCall(url,HttpMethod.GET,null,UpcomingEventsResponse.class);
}
private <T> T makeCall(String url,
HttpMethod method,
HttpEntity<Object> httpEntity,
Class<T> outClass) {
return restTemplate.exchange(url, method, httpEntity, outClass).getBody();
}
private <T> CompletableFuture<T> makeCallAsync(String url,
HttpMethod method,
HttpEntity<Object> httpEntity,
Class<T> outClass) {
return CompletableFuture.completedFuture(restTemplate.exchange(url, method, httpEntity, outClass).getBody());
}
}
and this is my scheduler class :
#Component
#RequiredArgsConstructor
#Slf4j
public class EventScheduler {
private final RestService restService;
//TODO change time
#Scheduled(cron = "0 */2 * * * *")
public void getAllEvents(){
long start = System.currentTimeMillis();
//TODO add token from database or env
UpcomingEventsResponse upcomingEvents = restService.getUpcomingEvents(null, "token");
List<ResultsItem> resultsItems = new ArrayList<>(upcomingEvents.getResults());
List<CompletableFuture<UpcomingEventsResponse>> completableFutures = new ArrayList<>();
int repeatTimes = upcomingEvents.getPager().getTotal() / upcomingEvents.getPager().getPerPage();
for (int i = 0; i < repeatTimes; i++) {
int page = i + 2;
CompletableFuture<UpcomingEventsResponse> events = restService.getUpcomingEvents(page, null, "token");
completableFutures.add(events);
}
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
log.info("Elapsed time: " + (System.currentTimeMillis() - start));
completableFutures.forEach(completableFuture -> {
try {
resultsItems.addAll(completableFuture.get().getResults());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
log.info("Size " + resultsItems.size());
log.info("Total " + upcomingEvents.getPager().getTotal());
}
}
and this is the error I'm getting in JDK 8:
peer not authenticated; nested exception is javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
and this is the error on JDK 10 or 11 :
javax.net.ssl.SSLException: No PSK available. Unable to resume
is there a better way to do this? and what is the problem? is this a bug?
The problem was in the Web Service, although I really can't understand the reason for the error in different JDKs. as far as I known this is a known bug and you can read more about it here
this implementation works just fine and you can use Apache HTTP Client with resttemplate but you can't use OkHttp or Apache HttpClient with Spring webflux WebService
The FCM Token ID has been generated and I want it to send to the PHP server and then store it in a variable. What should be the approach?
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
private void sendRegistrationToServer(String token) {
}
PHP Code
<?php
$token = $_POST["tokenid"];
echo ($token);
?>
You can store you FCM-Id in Preference and then pass this FCM-Id to backend pass it as a parametr using API calling. here below i'm get FCM-Id and pas to PHP using API.
MyFirebaseInstanceIDService.java
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
Context context;
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
// [START refresh_token]
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
context = getApplicationContext();
AppPreference.setStringPref(context, AppPreference.PREF_SIGNUP_FCM_ID, AppPreference.PREF_KEY.PREF_KEY_FCM_ID,
refreshedToken);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(refreshedToken);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
* <p>
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
Map<String, String> params = new HashMap<String, String>();
String device_id = Common.getDeviceId(this);
params.put(FCM_TOKEN, token);
params.put(DEVICEID, device_id);
params.put(DEVICE_TYPE, device_type);
JsonObjectRequest request = new JsonObjectRequest(FCM_TOKEN_URL, new JSONObject(params),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
parseJsonPersonalDetail(response);
} catch (Exception e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error.networkResponse != null) {
int statusCode = error.networkResponse.statusCode;
NetworkResponse response = error.networkResponse;
Log.d("testerror", "" + statusCode + " " + response.data);
}
}
}) {
#Override
public Map<String, String> getHeaders() {
Map<String, String> headers = new HashMap<String, String>();
headers.put("User-agent", "Mozilla/5.0 (TV; rv:44.0) Gecko/44.0 Firefox/44.0");
return headers;
}
};
Common.setVolleyConnectionTimeout(request);
ApplicationClass.getInstance().getRequestQueue().add(request);
}
/**
* <b>Description</b> - Get back response for calling callUserDetailSave API
*
* #param jsonObject - Pass API response
*/
private void parseJsonPersonalDetail(JSONObject jsonObject) {
try {
Log.i("get response", "get response" + jsonObject);
if (jsonObject.toString().contains(Constant.JSON_KEY.MSG)) {
String message = jsonObject.getString(Constant.JSON_KEY.MSG);
String status = jsonObject.getString(Constant.JSON_KEY.CODE);
}
} catch (Exception e) {
e.getStackTrace();
}
}
}
Here first i'm get FCM id then call API method sendRegistrationToServer and pass token in API as a paramter so back-end developer get this token from API parameter.
Here i'm pass three parameters
params.put(FCM_TOKEN, token);
params.put(DEVICEID, device_id);
params.put(DEVICE_TYPE, device_type);
device_id and device_type pass because it's my requirment.
Add dependency in app level gradle file for calling Volley API call :
implementation 'com.android.volley:volley:1.1.0'
Checkout i'm created Demo for you: Demo
Volley Libraries Example :
Tutorial 1
Tutorial 2
Tutorial 3
Is there a Spring Boot Actuator Health Check endpoint for SQS? I have built a SQS consumer and I want to check if SQS is up and running. I am not using JMSlistener for connecting to SQS but rather using Spring Cloud Libraries.
I implemented the below health check endpoint. This returns the below error when I delete the queue and try to hit the health check endpoint. If there is a connectivity issue or if the SQS service goes down , will I be getting a similar error which will eventually cause the health check endpoint to fail?
com.amazonaws.services.sqs.model.QueueDoesNotExistException: The
specified queue does not exist for this wsdl version. (Service:
AmazonSQS; Status Code: 400; Error Code:
AWS.SimpleQueueService.NonExistentQueue; Request ID:
cd8e205d-dc43-535e-931f-7332733bd16c)
public class SqsQueueHealthIndicator extends AbstractHealthIndicator {
private final AmazonSQSAsync amazonSQSAsync;
private final String queueName;
public SqsQueueHealthIndicator(AmazonSQSAsync amazonSQSAsync, String queueName) {
this.amazonSQSAsync = amazonSQSAsync;
this.queueName = queueName;
}
#Override
protected void doHealthCheck(Health.Builder builder) {
try {
amazonSQSAsync.getQueueUrl(queueName);
builder.up();
} catch (QueueDoesNotExistException e) {
e.printStackTrace();
builder.down(e);
}
}
}
Beans
#Bean
SqsQueueHealthIndicator queueHealthIndicator(#Autowired AmazonSQSAsync amazonSQSAsync, #Value("${sqs.queueName}") String queueName) {
return new SqsQueueHealthIndicator(amazonSQSAsync, queueName);
}
#Bean
SqsQueueHealthIndicator deadLetterQueueHealthIndicator(#Autowired AmazonSQSAsync amazonSQSAsync, #Value("${sqs.dlQueueName}") String deadLetterQueueName) {
return new SqsQueueHealthIndicator(amazonSQSAsync, deadLetterQueueName);
}
You have to write a custom health check like below to check your queue exists or not by calling getQueueUrl using AWS Java SDK lib.
#Component
public class SQSHealthCheck implements HealthIndicator {
#Override
public Health health() {
int errorCode = check(); // perform some specific health check
if (errorCode != 0) {
return Health.down()
.withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
public int check() {
/**
your logic to check queue exists or not using by calling getQueueUrl . e.g you will get queue url of a queue named "SampleQueue" like https://sqs.us-east-1.amazonaws.com/12XXX56789XXXX/SampleQueue
**/
return 0; // 0 or 1 based on result
}
}