camel cxf proxy doesnt work with http endpoint - java

My requirement is to have a proxy web service which will receive the request from clients and then route through camel,enrich it and forward it to real webservice at other clients place ,get response and send it back to the original requestor.
i basically looked at camel-cxf-proxy example (http://camel.apache.org/cxf-proxy-example.html) and camel-cxf-example in camel distribution.Its exactly similar to camel-cxf-proxyand came up with this route
<from uri="cxf:bean:soapMessageEndpoint?dataFormat=MESSAGE" />
<camel:convertBodyTo type="java.lang.String"></camel:convertBodyTo>
<to ref="XService"></to>
where endpoints are
<endpoint id="XService" uri="http://xx.xx.xxx.xx:8080/X_Service" />
<cxf:cxfEndpoint id="soapMessageEndpoint" address="http://localhost:8181/ProviderInformationDirectoryService" wsdlURL="wsdl/HPD_ProviderInformationDirectory.wsdl" endpointName="s:ProviderInformationDirectory_Port_Soap" serviceName="s:ProviderInformationDirectory_Service" xmlns:s="urn:ihe:iti:hpd:2010"/>
As you can see the second service is http endpoint.And first is the camel-cxf proxy.I just have the wsdl and at this point there is no need for impl.the dataformat is MESSAGE as i need the entire soap envelope to be sent to second web service and there are some useful headers in request from client.But when i run this route with a sample soap envelope it always comes up with 500 response.I am thinking that message sent to real webservice is not what it expects.
I tried trace on camel route but it didnt show much.I was hoping it will show real request to http endpoint.i tried to configure interceptor but that didnt work either.Trace only shows following
Failed delivery for (MessageId: ID-ALHCAN0437-63941-1354828653539-45-2 on ExchangeId: ID-ALHCAN0437-63941-1354828653539-45-1). Exhausted after delivery attempt: 1 caught: org.apache.camel.component.http.HttpOperationFailedException: HTTP operation failed invoking http://X:8080/X_Service with statusCode: 500
I also tried the following which seems to be working.
<from uri="cxf:bean:soapMessageEndpoint?dataFormat=MESSAGE" />
<camel:convertBodyTo type="java.lang.String"></camel:convertBodyTo>
<to uri="bean:callRemoteWS"></to>
callRemoteWS (callRemoteMethod) gets the soapenvelope as string and makes a HTTPPost request to above endpoint , returns back the response.
public String callRemoteMethod(String request) throws Exception{
HttpClient client = new HttpClient();
BufferedReader br = null;
PostMethod method = new PostMethod("http://x.x.x.x:8080/X_Service");
RequestEntity entity =new StringRequestEntity(request);
method.setRequestEntity(entity);
try{
int returnCode = client.executeMethod(method);
if (returnCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + method.getStatusLine());
return "Error";
}
// Read the response body.
byte[] responseBody = method.getResponseBody();
System.out.println(new String(responseBody));
// Deal with the response.
// Use caution: ensure correct character encoding and is not binary data
return new String(responseBody);
} finally {
method.releaseConnection();
if(br != null) try { br.close(); } catch (Exception fe) {}
}
}
I am confused why the simple camel-cxf proxy with http webservice didnt work and the second one works (it should and it does :P).Is the code i have ok.It doesnt seem right to me.I am pretty sure some exchange property is set wrong or content sent to real webservice is wrong.The content got from the proxy is used to make the Httppost call in second route.so the content from proxy cannot be wrong.when it is got from exchange and send to real webservice something goes wrong. Can anybody throw some light on it.

I think it was a silly mistake on my part .Soap action header had a different operation and the payload was for a different method.I was invoking the wrong operation with the payload

Related

Java Unirest sends POST request with empty JSON to server running on localhost but works fine when sending the same request to cloud server?

I am building an agent in Java which has to solve games using a planner. The planner that I am using runs as a service on the cloud, and thus anybody can send HTTP requests to it and get a response. I have to send to it a JSON with the following content: {"domain": "string containing the domain's description", "problem": "string containing the problem to be solved"}. As a response I get a JSON that contains the status and the result, which might be a plan or not, depending on whether there was some problem or not.
The following piece of code allows me to call the planner and receive its response, retrieving the JSON object from the body:
String domain = readFile(this.gameInformation.domainFile);
String problem = readFile("planning/problem.pddl");
// Call online planner and get its response
String url = "http://solver.planning.domains/solve";
HttpResponse<JsonNode> response = Unirest.post(url)
.header("accept", "application/json")
.field("domain", domain)
.field("problem", problem)
.asJson();
// Get the JSON from the body of the HTTP response
JSONObject responseBody = response.getBody().getObject();
This code works pefectly fine and I don't have any kind of problem with it. Since I have to do some heavy testing on the agent, I prefer to run the server on localhost, so that the service doesn't get saturated (it can only process one request at a time).
However, if I try to send a request to the server running on localhost, the body of the HTTP request that the server receives is empty. Somehow, the JSON is not sent and I am receiving a response that contains an error.
The following piece of code illustrates how I am trying to send a request to the server running on localhost:
// Call online planner and get its response
String url = "http://localhost:5000/solve";
HttpResponse<JsonNode> response = Unirest.post(url)
.header("accept", "application/json")
.field("domain", domain)
.field("problem", problem)
.asJson();
For the sake of testing, I had previously created a small Python script that sends the same request to the server running on localhost:
import requests
with open("domains/boulderdash-domain.pddl") as f:
domain = f.read()
with open("planning/problem.pddl") as f:
problem = f.read()
data = {"domain": domain, "problem": problem}
resp = requests.post("http://127.0.0.1:5000/solve", json=data)
print(resp)
print(resp.json())
When executing the script, I get a correct response, and it seems that the JSON is sent correctly to the server.
Does anyone know why this is happening?
Okay, fortunately I have found an answer for this issue (don't try to code/debug at 2-3AM folks, it's never going to turn out right). It seems that the problem was that I was specifying what kind of response I was expecting to get from the server instead of what I was trying to send to it in the request's body:
HttpResponse response = Unirest.post(url)
.header("accept", "application/json")...
I was able to solve my problem by doing the following:
// Create JSON object which will be sent in the request's body
JSONObject object = new JSONObject();
object.put("domain", domain);
object.put("problem", problem);
String url = "http://localhost:5000/solve";
<JsonNode> response = Unirest.post(url)
.header("Content-Type", "application/json")
.body(object)
.asJson();
Now I am specifying in the header what type of content I am sending. Also, I have create a JSONObject instance that contains the information that will be added to the request's body. By doing this, it works on both the local and cloud servers.
Despite of this, I still don't really get why when I was calling the cloud server I was able to get a correct response, but it doesn't really matter now. I hope that this answer is helpful for someone who is facing a similar issue!

CamelHttpResponseCode is null on service error

I'm new to camel and writing a small POC to implement in an existing application. Application takes a xml request as input which contains the requested services and relevant data. It then calls those services one by one.
When a service is called successfully then I retrieve the http response code in a processor like below and do further logic:
Object code = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE);
if(null!=code && code instanceof Integer)
{
responseCode = (Integer) code;
}
In success case, responseCode received = 201
Based on the responseCode, I know if the service call is successful and then proceed with the next one.
However, I tried to produce the negative scenario by making the service url incorrect and can't see the http response code anymore:
Original service url - http://xxx:0000/.../.../.../.../...
Modified service url - http://xxx:0000/.../.../.../.../abc/...
In failure case, responseCode received = null
In postman, I get the below error:
org.apache.camel.http.common.HttpOperationFailedException: HTTP
operation failed invoking http://xxx:0000/.../.../.../.../abc/...
with statusCode: 404 at
org.apache.camel.component.http.HttpProducer.populateHttpOperationFailedException(HttpProducer.java:274)
at
org.apache.camel.component.http.HttpProducer.process(HttpProducer.java:183)
I don't know why exchange doesn't contain the http response code when it's present in the error message in the postman.
I'm using onException to handle any exceptions and then calling a processor to process the flow further:
<camel:onException>
<camel:exception>java.lang.Exception</camel:exception>
<camel:process ref="xxxProcessor" />
</camel:onException>
I think I can consider responseCode=null as failure and proceed with my logic but want to understand why response code is being returned as null.
Thanks in advance!
I figured it out. It seems that in case of service exception, an instance of org.apache.camel.http.common.HttpOperationFailedException is thrown and the http status code is present in it. It can be retrieved in the processor like below:
Exception e = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
if(null!=e && e instanceof HttpOperationFailedException)
{
HttpOperationFailedException httpOperationFailedException = (HttpOperationFailedException)e;
responseCode=httpOperationFailedException.getStatusCode();
}
The accepted answer helped me and it might have been valid! In the camel version I'm usin (2.20.1), getting the exception via the property does not seem to work. The following does
HttpOperationFailedException httpOperationFailedException = exchange.getException(HttpOperationFailedException.class);
if(null!=e) {
responseCode = httpOperationFailedException.getStatusCode());
}

Making a POST request using Camel

I have a camel route configured for reading from a JMS queue and POST it to a service.
My route is :
from("jms:queue")
.marshal()
.json(JsonLibrary.GSON)
.setHeader(Exchange.CONTENT_TYPE,constant("application/json"))
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.process(new Processor1())
.to("https4:xxxxxx?throwExceptionOnFailure=false")
.process(new MyProcessor())
My Configuration :
HttpComponent httpc = getContext().getComponent("http4",HttpComponent.class);
httpc.setHttpConfiguaration(customHttpConfig())
and in customHttpConfig i set my auth details.
I am getting a 400 error from the server. But i am able to hit the server from Postman api and get successfull response.
In my Processor1 class ( before making the request), i am able to print the body of the message, which contains a json representation of my object.
But in the processor after the POST request, i am doing this and getting below responses:
Message in = exchange.getIn();
in.getBody(String.class); // print the error code 400
HttpServletRequest request = in.getBody(HttpServletRequest.class)// This is null.
Anything i am doing wrong? Do i need to set the message Content to the body of my Post Request?
It will not be String.class:
in.getBody(String.class);
First check the type of server response, then try to print or log exchange body.
It should be HttpServletResponse:
HttpServletRequest request = in.getBody(HttpServletRequest.class)

How to send a POST request with parameters to an endpoint via JBoss HttpRouter?

I'm working on an ESB project and I need to call a REST service using a POST request. HttpRouter seems to be the right way to do it since it supports both GET and POST methods but I can't find a way to inject parameters inside my call.
How can I do that ?
You can try Apache HTTP library. It's very easy to use and have comprehensive set of class needed to manipulate HTTP request.
Found the answer... It was pretty dumb. All you need to do is to inject parameters inside the Message object and they will be in the body of the request. Here is a sample code created by JBoss and found from a unit test of HttpRouter :
final ConfigTree tree = new ConfigTree("WrappedMessage");
tree.setAttribute("endpointUrl", "http://127.0.0.1:8080/esb-echo");
tree.setAttribute("method", "post");
tree.setAttribute("unwrap", "false");
tree.setAttribute("MappedHeaderList", "SOAPAction, Content-Type, Accept, If-Modified-Since");
HttpRouter router = new HttpRouter(tree);
Message message = MessageFactory.getInstance().getMessage(type);
message.getBody().add("bar");
Message response = router.process(message);
String responseBody = (String)response.getBody().get();
String responseStr = null;
if (deserialize)
responseStr = Encoding.decodeToObject(responseBody).toString();
else
responseStr = responseBody;
return responseStr;

My socket client only seems to receive the first response from a HTTP server. Why?

I am trying to develop a class that allows me to run a socket on a thread, and that at any time allows me to send through it data, as well as receive a notifications when data arrives. It should assume no things such as only receiving a message after it has sent a message first, etc.
By some reason, the following code is printing the response for only the first request:
public static void main(String[] args) throws IOException {
TCPClient client = new TCPClient(new TCPClientObserver());
client.connect("www.microsoft.com", 80);
sleep(1000);
client.send("HTTP GET");
sleep(5000);
client.send("XYZ");
}
printing
echo: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
echo: <HTML><HEAD><TITLE>Bad Request</TITLE>
echo: <META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
echo: <BODY><h2>Bad Request - Invalid URL</h2>
echo: <hr><p>HTTP Error 400. The request URL is invalid.</p>
echo: </BODY></HTML>
Here is the core logic of the socket:
echoSocket = new Socket("www.microsoft.com", 80);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
while (true) {
String response = in.readLine();
if (response != null)
System.out.println("echo: " + response);
}
I guess the problem lies in my loop?
The full test code of my app can be seen here:
http://codepad.org/bmHwct35
Thanks
The problem is not the loop, but rather the first request you send. "HTTP GET" is invalid request and the server should respond with "400 Bad request", then close the connection. That's why you don't get response for your second message. Try a valid HTTP request e.g. "GET / HTTP/1.1\r\nHost: www.microsoft.com\r\n\r\n" instead. HTTP 1.1 connections are keep-alive by default, so you'll be able to send several of them and receive subsequent responses.
Assuming the HTTP 400 is what you expected, you need to break out of your loop if readLine() returns null. This is usually written like this:
while ((line = in.readLine()) != null)
{
// ...
}
The first you send is an invalid request and after replying the server will close the connection. In your code you are then stuck in the while (true) loop as you will keep getting null back from readLine as the connection/stream is closed (end of stream reached).
while (true) { // <-- never terminates
String response = in.readLine();
if (response != null) // <- now null all the time
System.out.println("echo: " + response);
}
The problem is that HTTP servers talk the HTTP protocol, and your client code is not talking the protocol properly. Instead it is opening a plain socket and writing random stuff that seems to be based on guesswork.
The HTTP protocol is specified in this document. If you read it, you will see that what you are doing is nothing like what a client is supposed to do.
I recommend that you don't attempt to implement your client this way. Implementing the client side of the HTTP protocol from scratch is too much work ... and the world does not need yet another flakey HTTP client. Either use the standard URL / HttpURLConnection APIs, or use a 3rd-party HTTP client library.
In your case, the 400 response is most likely a consequence of sending a malformed request. An HTTP GET request (indeed any HTTP request) is supposed to include the target URL in the first line. Read the spec.

Categories