I have Azure logic app with request trigger. I want to trigger this logic app from my java application. So, I am trying to call the request trigger url from my java API.
It is working fine if i am using DefaultHttpClient but getting 401 on calling it using RestTemplate in java.
DefaultHttpClient code:
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(
"{url of azure logic app trigger}");
//StringEntity input = new StringEntity("{\"qty\":100,\"name\":\"iPad 4\"}");
//input.setContentType("application/json");
//postRequest.setEntity(input);
HttpResponse response = httpClient.execute(getRequest);
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
httpClient.getConnectionManager().shutdown();
return("Success");
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return("Error");
} catch (UnsupportedOperationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return("Error");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return("Error");
}
RestTemplate Code
#Service
public class SampleService {
#Autowired HttpClientService<String, String> httpClientService;
public String callURL() {
ResponseErrorHandler responseErrorHandler = new ResponseErrorHandler() {
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
System.out.print(response.toString());
return false;
}
#Override
public void handleError(ClientHttpResponse response) throws IOException {
// TODO Auto-generated method stub
}
};
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString("{logic app url}")
// Add query parameter
.queryParam("api-version", {api-version})
.queryParam("sp", {sp})
.queryParam("sv", {sv})
.queryParam("sig",{sig});
RequestDetailsDAO requestDetails = new RequestDetailsDAO(builder.build().toUri().toString(), HttpMethod.GET);
String response = httpClientService.execute(requestDetails, null, responseErrorHandler, String.class);
return response.toString();
HttpClientService.java
#Service
public class HttpClientService<T, V> {
public RestTemplate restTemplate;
public HttpClientService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.setConnectTimeout(Duration.ofSeconds(5)).setReadTimeout(Duration.ofSeconds(5)).build();
}
public V execute(RequestDetailsDAO requestDetails, HttpEntity<T> entity, ResponseErrorHandler errorHandler,
Class<V> genericClass) {
restTemplate.setErrorHandler(errorHandler);
ResponseEntity<V> response = restTemplate.exchange(requestDetails.getUrl(), requestDetails.getRequestType(), entity, genericClass);
return response.getBody();
}
}
RequestDetailsDAO.java
public class RequestDetailsDAO {
private String url;
private HttpMethod requestType;
public RequestDetailsDAO(String url, HttpMethod requestTyp) {
super();
this.url = url;
this.requestType = requestTyp;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public HttpMethod getRequestType() {
return requestType;
}
public void setRequestType(HttpMethod requestType) {
this.requestType = requestType;
}
#Override
public String toString() {
return "RequestDetails [url=" + url + ", requestType=" + requestType + "]";
}
}
So, it seems that there's nothing special about LogicApps being called using RestTemplate.
It's just that RestTemplate by default URL encode the Uri given in parameter, and DefaultHttpClient does not - reference: apache vs resttemplate
In case of LogicApp URL, there is this "sp" parameter which is already URL endcoded, when you copy it from LogicApp -
"%2Ftriggers%2Fmanual%2Frun", so you need to decode that and pass "/triggers/manual/run" to UriComponentsBuilder. And then it works.
My code:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> request = new HttpEntity<>(requestDto, headers);
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString("https://prod-123901.westeurope.logic.azure.com:443/workflows/<workflow_id>/triggers/manual/paths/invoke")
.queryParam("api-version", "2016-10-01")
.queryParam("sp", "/triggers/manual/run")
.queryParam("sv", "1.0")
.queryParam("sig", "<your_sig>");
restTemplate.exchange(builder.build().toUri().toString(), HttpMethod.POST, request, Void.class);
update:
requestDto here is your custom dto object that goes in HTTP Body, like for example object of class:
public class RequestDto {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Please try with the simple standalone code with RestTemplate and check. I provide below small snippet.
try {
ResponseEntity<ResponseVO> response = restTemplate.exchange({uri of azure logic app trigger}, HttpMethod.GET, request, ResponseVO.class);
} catch (HttpStatusCodeException ex) {
int statusCode = ex.getStatusCode().value();
System.out.println("Status Code :"+statusCode);
ResponseEntity<?> resEntity = ResponseEntity.status(ex.getRawStatusCode()).headers(ex.getResponseHeaders())
.body(ex.getResponseBodyAsString())
}
Here ResponseVO.class is the Response to be mapped to an object, in this case, you can set your own class. In this catch block, you can find the exception details.
Related
I have this code, It uses the java java.net.http.HttpClient :
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class test {
private static String authorizationHeader = "Bearer ";
public static int MAX_RESEND = 5;
public static int TIME_OUT = 150000;
public static String url = "http://127.0.0.1:5000/api/test";
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.connectTimeout(Duration.ofMinutes(3))
.build();
public static HTTPResponse postHttpRequest(HttpClient httpClient, String uri, String body){
HttpResponse.BodyHandler<String> handler = HttpResponse.BodyHandlers.ofString();
HttpRequest request = HttpRequest.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.timeout(Duration.ofMinutes(5))
.uri(URI.create(uri))
.header("Content-Type", "application/json")
.header("Authorization", authorizationHeader)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
CompletableFuture<HttpResponse<String>> response = httpClient.sendAsync(request, handler)
.thenComposeAsync(r -> tryResend(httpClient, request, handler, 1, r, TIME_OUT));
String getResponse = null;
Integer getResponseStatusCode = null;
try {
getResponse = response.thenApply(HttpResponse::body).get(3, TimeUnit.MINUTES);
getResponseStatusCode = response.get().statusCode();
return new HTTPResponse(getResponseStatusCode, getResponse, null) ;
} catch (Exception e) {
return new HTTPResponse(500, e.toString(), e.getMessage());
}
}
public static <T> CompletableFuture<HttpResponse<T>> tryResend(HttpClient client, HttpRequest request, HttpResponse.BodyHandler<T> handler, int count, HttpResponse<T> resp, long timeSleep) {
try {
Thread.sleep(timeSleep);
if (resp.statusCode() == 200 || count >= MAX_RESEND) {
return CompletableFuture.completedFuture(resp);
} else {
return client.sendAsync(request, handler)
.thenComposeAsync(r -> tryResend(client, request, handler, count+1, r, timeSleep));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String body = "{\"app\":\"hi\"}";
HTTPResponse hResponseOrigin = postHttpRequest( httpClient , url , body);
Integer statusCodeOriginResponse = hResponseOrigin.getStatusCode();
String msgOriginResponse = hResponseOrigin.getResponse();
}
}
class HTTPResponse {
private Integer statusCode;
private String response;
private String exception;
public HTTPResponse(Integer statusCode, String response, String exception) {
this.statusCode = statusCode;
this.response = response;
this.exception = exception;
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
public String getException() {
return exception;
}
public void setException(String exception) {
this.exception = exception;
}
}
The code tries to do n recursive-requests when the first response of the request is not 200.
The issue always appears on the second retry.
I always get this exception:
java.util.concurrent.TimeoutException
example:
postHttpRequest ---------------------------
http://127.0.0.1:5000/api/test
tryResend ------------------------------------------------------
count zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
1
res get tryResend ----------zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxx
{"app":"hi"}
status code: 500
tryResend ------------------------------------------------------
count zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2
res get tryResend ----------zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxx
{"app":"hi"}
msgOriginResponse xxxxxxxxxxxxxxxx----------------------------------------------------------------xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
java.util.concurrent.TimeoutException
msgOriginResponse end xxxxxxxxxxxxxxxxx----------------------------------------------------------------xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
How can I fix it?? any recomendation ?
#Service
public class PokemonManager implements PokemonService {
private HttpResponse<String> getStringHttpResponseByUrl(final String url) {
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET().header("accept", "application/json")
.uri(URI.create(url)).build();
HttpResponse<String> httpResponse = null;
try {
httpResponse = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return httpResponse;
}
private <T> T getObjectResponse(T t, String url) {
ObjectMapper objectMapper = new ObjectMapper();
try {
t = objectMapper.readValue(getStringHttpResponseByUrl(url).body(), new TypeReference<>() {
});
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return t;
}
private List<Pokemon> getAllPokemonsAsList() {
final String POSTS_API_URL = "https://pokeapi.co/api/v2/pokemon?limit=10000";
PokeApiResponse pokeApiResponse = new PokeApiResponse();
pokeApiResponse = getObjectResponse(pokeApiResponse, POSTS_API_URL);
System.out.println(pokeApiResponse);
return pokeApiResponse.results;
}
#Override
public List<Pokemon> getAll() {
return getAllPokemonsAsList();
}
I have a code as above. If I do not use generics in the "getObjectResponse" method, the code works fine. However, when I use generics, the type of "t" becomes "LinkedHashMap" instead of "PokeApiResponse", and the code crashes. How can I fix this problem?
Generally you would use it:
objectMapper.readValue("yourJSONHere", PokeApiResponse.class);
If you wanted a Generic T response perhaps this would work
private <T> T getGeneric(Class<T> clazz, String json) throws IOException {
return new ObjectMapper().readValue(json, clazz);
}
Example:
Pokemon charmander = getGeneric(Pokemon.class, "{\n" +
" \"name\": \"charmander\"\n" +
"}");
You are not passing enough information for ObjectMapper to parse the JSON this way. Also there is no need to pass the instance of response, you can use the Class instead. I would also extract json parsing logic to separate method:
public static <T> T jsonToModel(String document, Class<T> type) throws IOException {
return new ObjectMapper().readValue(document, type);
}
private List<Pokemon> getAllPokemonsAsList() {
final String postsApiUrl = "https://pokeapi.co/api/v2/pokemon?limit=10000";
final HttpResponse<String> httpResponse = getStringHttpResponseByUrl(postsApiUrl);
final PokeApiResponse pokeApiResponse = jsonToModel(pokeApiResponse, PokeApiResponse.class);
System.out.println(pokeApiResponse);
return pokeApiResponse.results;
}
I'm trying to mock a method call from class called RestClient in another called DiscoveryAdapter but as and when i'm trying to do a doReturn it throws a null pointer exception.
In test i'm trying to spy the restClient object in order to mock the method call in DiscoveryAdapter.discovery method but with it throws a null pointer exception when doReturn is called.
Please check the code below.
RestClient.class
#Component
#Scope("prototype")
public class RestClient {
private static final Logger logger = LoggerFactory.getLogger(RestClient.class);
private RestTemplate restTemplate = null;
private PoolingHttpClientConnectionManager syncConnectionManager;
public void init() {
restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(buildhttpClient()));
}
public String queryRestEndpoints(HereMapsImpl mapType,String basePath,boolean isSSl) {
URI uriObject = null;
String uriPath = mapType.returnUri();
init();
try {
uriObject = RestUtils.buildUriFromString(basePath, isSSl, uriPath);
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logger.info("rest api is {}",uriObject);
//spring api
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> requestEntity = new HttpEntity<String>("",headers);
//rest api call with uriObject
ResponseEntity<String> responseEntity = restTemplate.exchange(uriObject,
HttpMethod.GET, requestEntity, String.class);
if(responseEntity.getStatusCodeValue() >=400 || responseEntity.getStatusCodeValue() <= 500)
logger.info("failed with status code {}",responseEntity.getStatusCodeValue() );
logger.info("checking my response");
logger.info("checking my response here {}",responseEntity.getBody());
return responseEntity.getBody();
}
private CloseableHttpClient buildhttpClient() {
CloseableHttpClient httpClient = null;
httpClient = HttpClientBuilder.create().setConnectionManager(getSyncConnectionManager())
.build();
return httpClient;
}
public PoolingHttpClientConnectionManager getSyncConnectionManager() {
syncConnectionManager = new PoolingHttpClientConnectionManager();
return syncConnectionManager;
}
DisoveryAdapter.class
#Component
public class DisoveryAdapter {
private static final Logger log = LoggerFactory.getLogger(DisoveryAdapter.class);
#Autowired
private RestClient restClient;
public void discovery() {
log.info("starting thread");
String response = restClient.queryRestEndpoints(eatDrink, completeUriPath, true);
log.info("oeat drink response {}",response);
}
}
DiscoveryAdapterTest.class
class HereMapsCheckImpTest {
private static final Logger log = LoggerFactory.getLogger(HereMapsCheckImpTest.class);
private RestClient restClient;
private HereMapsCheckImp hereMaps;
#Before
public void init() {
hereMaps = new HereMapsCheckImp();
restClient = new RestClient();
}
#Test
public void test() {
RestClient spyRestClient = spy(restClient);
log.info("with spring {}",spyRestClient);
doReturn("{\n" +
" color: \"red\",\n" +
" value: \"#f00\"\n" +
"}").when(spyRestClient).queryRestEndpoints(any(),any(),any());
hereMaps.discovery();
verify(spyRestClient).queryRestEndpoints(any(),any(),any());
}
}
I have the method:
public HTTPResult get(String url) throws Exception{
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return new HTTPResult(response.getBody(), response.getStatusCode().value());
}
catch (ResourceAccessException e) {
String responseBody = e.getCause().getMessage();
JSONObject obj = new JSONObject(responseBody);
return new HTTPResult(obj.getString("responseBody"), Integer.parseInt(obj.getString("statusCode")));
}
}
I want to do unit testing for it and i am not sure how to proceed:
public class MockHttpServerTest {
private static final int PORT = 51234;
private static final String baseUrl = "http://localhost:" + PORT;
private MockHttpServer server;
private SimpleHttpResponseProvider responseProvider;
private HttpClient client;
#Before
public void setUp() throws Exception {
responseProvider = new SimpleHttpResponseProvider();
server = new MockHttpServer(PORT, responseProvider);
server.start();
client = new DefaultHttpClient();
}
I am getting RED for MockHttpServer & SimpleHttpResponseProvider which should be part of org.apache.wink.client.*; which i am importing. so why do i have red ones? is there some simple way to unit test it?
HTTPResult return me response code and message.
I wrote a Web API using Apache CXF. When I use HttpServletRequest.getParamter() in a post method, it return null.Here is the code:
#Path("/")
public class TokenService extends DigiwinBaseService {
private static void printRequest(HttpServletRequest httpRequest) {
System.out.println("\n\n Headers");
Enumeration headerNames = httpRequest.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
System.out.println(headerName + " = " + httpRequest.getHeader(headerName));
}
System.out.println("\n\n Parameters");
Enumeration params = httpRequest.getParameterNames();
while (params.hasMoreElements()) {
String paramName = (String) params.nextElement();
System.out.println(paramName + " = " + httpRequest.getParameter(paramName));
}
System.out.println("\n\n Row data");
System.out.println(extractPostRequestBody(httpRequest));
}
private static String extractPostRequestBody(HttpServletRequest request) {
if ("POST".equalsIgnoreCase(request.getMethod())) {
Scanner s = null;
try {
s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
} catch (IOException e) {
e.printStackTrace();
}
return s.hasNext() ? s.next() : "null";
}
return "null";
}
#POST
#Consumes("application/x-www-form-urlencoded")
public Response Authorize(#FormParam("param") String param,
#FormParam("param2") String param2,#Context HttpServletRequest httpRequest) throws OAuthSystemException {
printRequest(httpRequest);
System.out.println("param:"+param);
System.out.println("param2:"+param2);
return Response.status(HttpServletResponse.SC_OK).entity("OK").build();
}
}
Here is the test code
public class HttpClientTest {
public static void main(String[] args) throws Exception{
String url4 = "/api/services/Test";
String host = "127.0.0.1";
HttpClient httpClient = new HttpClient();
httpClient.getHostConfiguration().setHost(host, 8080, "http");
HttpMethod method = postMethod(url4);
httpClient.executeMethod(method);
String response = method.getResponseBodyAsString();
System.out.println(response);
}
private static HttpMethod postMethod(String url) throws IOException{
PostMethod post = new PostMethod(url);
post.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=gbk");
NameValuePair[] param = {
new NameValuePair("param","param1"),
new NameValuePair("param2","param2"),} ;
post.setRequestBody(param);
post.releaseConnection();
return post;
}
}
Here is the print out :
Headers
content-type = application/x-www-form-urlencoded;charset=gbk
user-agent = Jakarta Commons-HttpClient/3.1
host = 127.0.0.1:8080
content-length = 26
Parameters
Row data
null
param:param1
param2:param2
Why the Parameters is null? How can i get post params using HttpServletRequest.getParamter()
CXF is consuming the POST data to fill the FormParams.
https://issues.apache.org/jira/browse/CXF-2993
The resolution is "won't fix". In the issue, they suggest to use a MultivaluedMap to recover all params, or use only the HttpServletRequest
Option 1
#POST
#Consumes("application/x-www-form-urlencoded")
public Response Authorize( MultivaluedMap<String, String> parameterMap, #Context HttpServletRequest httpRequest) throws OAuthSystemException {
//parameterMap has your POST parameters
Option 2
#POST
#Consumes("application/x-www-form-urlencoded")
public Response Authorize( #Context HttpServletRequest httpRequest) throws OAuthSystemException {
//httpRequest.getParameterMap() has your POST parameters