404 error while invoking a method in webservice - web-services

I am pretty new to webservice. I am using spring mvc and webservice to upload a file to the server. In the spring controller I tried to add the parameters in a multivalue map like the one below
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("caption", "Test Caption");
formData.add("file",new FileSystemResource("/home/mytxt");
formData.add("jsonData",imageJson);
my httpheader and httpentity looks like the one below
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
final HttpEntity<MultiValueMap<String,Object>> requestEntity = new HttpEntity<>(
formData, requestHeaders);
in the service side my method looks like
#Path("/addImage")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response copyFromLocal(
#FormDataParam("file") InputStream uploadedInputStream ) throws IOException
{
return null;
}
up to this point everything is fine, but when I use the method like the one below, the method is not invoked
#POST
#Path("/addImage")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response copyFromLocal(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition content)
throws IOException
{
}
client code is
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("caption", "Test Caption");
formData.add("file",new FileSystemResource("/home/txt"));
formData.add("jsonData",imageJson);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
final HttpEntity<MultiValueMap<String,Object>> requestEntity = new HttpEntity<>(
formData, requestHeaders);
responseFromService = this.baseAdapter.makeRequest(HttpMethod.POST,
requestEntity, relativeURL, String.class,true);
BaseAdapter class uses Spring RestTemplate to post the url.
I want to get all the parameters present in the map in controller to be passed to the method in the service side. Can any one help me in fixing the issue? Any help is appreciated.

I see you have specified two #FormDataParam("file") annotation,on two different argument,i think it should be applied to only one.
#POST
#Path("/addImage")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response copyFromLocal(
InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition content)
throws IOException {
}

Related

Camel Restlet sends response to client asynchronously

I have a scenario that I'm using camel-restlet component to receive post requests, I'm forwarding these requests to an external web service, after receiving the response code from the external service, I need to add this response code to my own response to the client asynchronously.
Im trying to save the response object to a hashMap where key is an unique serial number generated based on the request content, once upon receiving the response from external web service, I can retrieve the response object from the hashMap using this unique key. Seems like restlet saves the response to exchange.getOut() message and sends back to the client synchronously which is not something I want. Not setting an out message would give me a nullPointerException.
route Class:
public class ReceiveRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("restlet:http://localhost:8083/api/atmp?restletMethod=post")
.to("activemq:queue:requestReceiveQueue");
from("activemq:queue:requestReceiveQueue")
.process(new RequestProcessor())
.to("activemq:queue:requestSendQueue");
from("activemq:queue:requestSendQueue")
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.to("jetty:http://localhost:8080/rest_api_demo/api/restService")
.bean("responseProcessor");
}
}
requestProcessor class:
public class RequestProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
Message message = exchange.getIn();
byte[] bytes = (byte[])message.getBody();
String body = new String(bytes);
String atmpId = GUIDGenerator.generateAtmpSerialNumber();
String terIndentifier = GUIDGenerator.generateTerminalIdentifier(body);
MapLookupHelper.insertResponse(atmpId, terIndentifier, exchange);
Map<String, Object> messageMap = new HashMap<String, Object>();
messageMap = FormatUtil.parseJson(body);
messageMap.put("ATMPId", atmpId);
exchange.getIn().setBody(messageMap.toString());
}
}
responseProcessor class
#Component
public class ResponseProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
Message in = exchange.getIn();
String responseCode = in.getHeader(Exchange.HTTP_RESPONSE_CODE).toString();
String body = in.getBody().toString();
Map<String, Object> resMap = new HashMap<String, Object>();
resMap = FormatUtil.parseJson(body);
String atmpId = resMap.get("ATMPId").toString();
Exchange ex = MapLookupHelper.getOutMessage(atmpId);
ex.getOut().setHeader("HostResponseCode", responseCode);
ex.getOut().setBody(resMap.toString());
}
}
I'm new to Apache Camel and would like to know if restlet is the right way to go, if not, any suggestion on how I can handle async responses to client in Camel? Is AsyncProcessor only solution to such scenario?
I think it's not issue of restlet. Your exchange pattern is InOut, that's why all jms-endpoint's waiting synchronously result of your .bean("responseProcessor").
Even if you change pattern to InOnly your client will not receive response asynchronously. I think you should make another route's architecture, like below:
from("restlet:http://localhost:8083/api/atmp_asyncRequest?restletMethod=post")
.process(exchange -> {
exchange.setProperty("uniqueRequestId", GUIDGenerator.generateAtmpSerialNumber());
})
.inOnly("seda:requestReceiveQueue")// here starts async processing of your request
.process(exchange -> {
exchange.getProperty("uniqueRequestId");
// make here response for client with generated request id
});
from("seda:requestReceiveQueue")
.process(exchange -> {
// prepare\process request if need
})
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.to("jetty:http://localhost:8080/rest_api_demo/api/restService")
.process(exchange -> {
exchange.getProperty("uniqueRequestId");
// save somewhere prepared response for client bound to generated request id
});
from("restlet:http://localhost:8083/api/atmp_getResponse?restletMethod=post")
.process(exchange -> {
String requestId = ;//extract request id from client's request
Object body = ;//find response that you saved asynchronously by extracted request id
// if response not found, then async processing request not ended, so you should send message to client to continue polling
exchange.getIn().setBody(body);
});
That will work if you haven't callback server for async responses on client's side.
Also you can use Seda component instead of jms, for queueing tasks between routes.

how to create PACT for multipart/form-data uploading cdc test

I`m trying to create cdc test for uploading file verifying. I use DIUS library. I do not find any examples how to work with .withFileUpload() in DIUS. My code for pact is next:
#Pact(provider = PROVIDER, consumer = CONSUMER)
public RequestResponsePact createPact(PactDslWithProvider builder) throws Exception {
DslPart responseBody = new PactDslJsonBody()
.stringType("resource", DESTINATION_FILENAME)
.stringType("requestId", null)
.stringType("code", "201")
.array("response")
.closeArray()
.asBody();
return builder.given("UploadOperation")
.uponReceiving("Upload operation")
.path("/files/upload")
.matchQuery("overwrite", "true")
.matchQuery("destination_filename", DESTINATION_FILENAME)
.withFileUpload("file",
".gitignore",
"multipart/form-data",
new byte[]{11,44,66,123,66}) // some bytes
.willRespondWith()
.status(201)
.body(responseBody)
.toPact();
}
Code for pact creation and verification:
#Test
#PactVerification
public void doTest() throws IOException {
String url = String.format("Http://localhost:%d/files/upload?overwrite=true&destination_filename=%s", PORT, DESTINATION_FILENAME);
// HttpEntity for request
HttpEntity multipart = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addBinaryBody("file", new byte[]{11,44,66,123,66},
ContentType.create("multipart/form-data"), ".gitignore")
.build();
// I make the request and get an answer
HttpResponse response = Request.Put(url)
.addHeader("Content-Type", "multipart/form-data;
boundary=j72BRjsEynnAqDw43KTlsjxoKWsjdF_tl6N5")
.body(multipart)
.execute()
.returnResponse();
String json = EntityUtils.toString(response.getEntity());
System.out.println("json=" + json);
JSONObject jsonObject = new JSONObject(json);
assertTrue(jsonObject.getString("code").equals("201"));
assertTrue(response.getStatusLine().getStatusCode() == 201);}
but when I run the test i get: json={"error": Missing start boundary}
java.lang.AssertionError: Pact Test function failed with an exception, possibly due to ExpectedButNotReceived(expectedRequests=[ method: PUT
path: /files/upload
query: [destination_filename:[test], overwrite:[true]]
headers: [Content-Type:multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p]
matchers: MatchingRules(rules={query=Category(name=query, matchingRules={overwrite=MatchingRuleGroup(rules=[RegexMatcher(regex=true, example=null)], ruleLogic=AND), destination_filename=MatchingRuleGroup(rules=[RegexMatcher(regex=test, example=null)], ruleLogic=AND)}), header=Category(name=header, matchingRules={Content-Type=MatchingRuleGroup(rules=[RegexMatcher(regex=multipart/form-data;(\s*charset=[^;]*;)?\s*boundary=.*, example=multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p)], ruleLogic=AND)}), path=Category(name=path, matchingRules={})})
generators: Generators(categories={})
body: OptionalBody(state=PRESENT, value=--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p
Content-Disposition: form-data; name="file"; filename=".gitignore"
Content-Type: multipart/form-data
,B{B
--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p--
)])
...
Caused by: org.json.JSONException: JSONObject["code"] not found.
Whats wrong in my code? I suppose something wrong with Content type, with 'boundary' part. But I dont know how to specify arbitrary boundary.
Maybe anybody knows another library where multipart/form-data uploading requests realized.
Thanks.
I found the solution from test example in DIUS library
contentType in .withFileUpload() and accordingly in .addBinaryBody() methods shouldn`t be "multipart/form-data". It may be "form-data" for example.
.addHeader in request method is not necessary because content type was already defined in body.

Springboot SOAP service unmarshalling Issue with the response from WebServiceTemplate

I am really bugged with an unmarshalling issue with the response from the SOAP service. I am using springboot application and WebServiceTemplate for calling an existing SOAP service. I am using below code to set up beans for marshalling and webservicetemplate. Any help is highly appreciated.
On calling webServiceTemplate.marshalSendAndReceive(request); I am expecting TravelResponse object but it is giving me JAXBElement<TravelResponse> object as response. I need help to understand
1) why is it giving above response instead of TravelResponse
2) How to convert to TravelResponse
Code snippet below:
#Bean
Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath("com.cater.trip.simple_api.trip.v1");
return jaxb2Marshaller;
}
#Bean
public WebServiceTemplate webServiceTemplate() throws Exception {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMessageFactory(getMessageFactory());
webServiceTemplate.setMarshaller(jaxb2Marshaller());
webServiceTemplate.setUnmarshaller(jaxb2Marshaller());
webServiceTemplate.setDefaultUri(defaultUri);
webServiceTemplate.setMessageSender(getMessageSender());
return webServiceTemplate;
}
#Bean
public SaajSoapMessageFactory getMessageFactory() {
return new SaajSoapMessageFactory();
}
#Bean
public HttpComponentsMessageSender getMessageSender() {
return new HttpComponentsMessageSender();
}
#Override
public Object getData( ) {
ObjectFactory clientFac = new ObjectFactory();
TravelRequest request = populateRequest(clientFac);
TravelResponse res = (TravelResponse) webServiceTemplate.marshalSendAndReceive(request);
return res;
}
As per Spring's doc, WebServiceTemplate.marshalSendAndReceive(Object requestPayload)
Sends a web service message that contains the given payload, marshalled by the configured Marshaller. Returns the unmarshalled payload of the response message, if any.
This will only work with a default uri specified!
So, you can do this to return the expected response.
JAXBElement<TravelResponse> res = (JAXBElement<TravelResponse>) webServiceTemplate.marshalSendAndReceive(request);
return res.getValue();
Try JaxbIntrospector.getValue to get the actual response from JAXB element.
TravelResponse response = JaxbIntrospector.getValue(jaxbElement);

Cannot call web api 2 post method with int parameter in URL in Unit Test using Http server

Please ignore the spelling mistake, I cannot copy code so I have typed the whole thing and changed name of controller and method.
WEB API 2
Controller:
// Controller name is Test
public HttpResponseMessage Method1(int param1) // Post method
{
// return string
}
If I create an object of controller in test case then it is working fine. But if I want to test in localhost using following code:
Unit Test:
public void Method1Test()
{
HttpResponseMessage response;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using(var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test?param1=1");
request.Content = new ObjectContent<int>(param1, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
Now, my test case is failing. I used the same code in different project and it worked. May be it is the way I am trying to call Post method. Is this the right way to call post method with Int parameter in URL?
In help page, under API column it shows:
POST api/test/param1={param1}
Also I have put some stop point in actual service I am cursor is not stopping at that point. Why?
If I want to call the same service from browser, what URL should I pass? Is it -
http://localhost:5022/api/test?param1=1
Or something else?
I figured it out. Following is the correct unit test method but this has some extra information which I have not provided earlier i.e., passing object as an input for the service.
private void Method1Test(ObjectClass obj)
{
HttpResponseMessage response = null;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using (var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test/1");
request.Content = new ObjectContent<ObjectClass>(obj, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
So the correct URL that I was looking for was
http://localhost:5022/api/test/1
Sorry, It took long to post this answer. This method is working like a charm for more then 2 years.

Resteasy, Make a Http-Put or Http-Post with Server-side Mock Framework of RestEasy

I wrote a Rest-Service which i would like to test.
I wanna run a JUnit test without having my server run. For this I am using the Server-side Mock Framework of RestEasy.
My question is, how can I make a Http-Put or Http-Post request with this framework with an marshalled Java Object in the Http-Body???
The Code below runs fine for an Http-Get, but how to make a Put or Post, maybe someone got some example code for this???
#Test
public void testClient() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(
MyClass.class);
dispatcher.getRegistry().addResourceFactory(noDefaults);
{
MockHttpRequest request = MockHttpRequest.get("/message/test/"
+ requestParam);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
}
}
A bit late response but , might have some use for someone.
This is how i usually test my PUT requests. Hope it helps
#Test
public void testPUT() throws Exception {
POJOResourceFactory noDefaults = new POJOResourceFactory(REST.class);
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addResourceFactory(noDefaults);
String url = "your_url_here";
MockHttpRequest request = MockHttpRequest.put(url);
request.accept(MediaType.APPLICATION_JSON);
request.contentType(MediaType.APPLICATION_JSON_TYPE);
// res being your resource object
request.content(res.toJSONString().getBytes());
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assert.assertEquals( HttpStatus.SC_CREATED,response.getStatus());
}