spring integration: How do I call the Spring Integration from Spring Controller? - spring

please, Can you help me?
All of source here it is.
(https://github.com/mcvzone/integration-tcp-test.git)
Thank you.
1. I created a spring integration-tcp-client context xml file.
<int:gateway id="gw"
service-interface="com.example.demo.module.SimpleGateway"
default-request-channel="input"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="1234"
single-use="true"
so-timeout="10000"/>
<int:channel id="input"/>
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="clientBytes2StringChannel"
connection-factory="client"
request-timeout="10000"
reply-timeout="10000"/>
<int:object-to-string-transformer id="clientBytes2String"
input-channel="clientBytes2StringChannel"/>
2. And I created a RestController.
#RestController
public class TcpController {
final GenericXmlApplicationContext context;
final SimpleGateway simpleGateway;
public TcpController(){
this.context = new GenericXmlApplicationContext();
context.load("classpath:META-INF/spring/integration/tcpClientServerDemo-context.xml");
context.registerShutdownHook();
context.refresh();
this.simpleGateway = context.getBean(SimpleGateway.class);
}
#RequestMapping("/tcp/test")
public String test(String name) {
//SimpleGateway simpleGateway = context.getBean(SimpleGateway.class);
String result = simpleGateway.send(name);
System.out.println("result : " + result);
return result;
}
}
3. I start spring boot and open 1234 port (new ServerSocket(1234)) and I call url.(http://localhost:8080/tcp/test)
4. It result is error.
java.lang.IllegalArgumentException: unable to determine a Message or payload parameter on method
.
.
.
at com.sun.proxy.$Proxy60.send(Unknown Source) ~[na:na]
at com.example.demo.TcpController.test(TcpController.java:25) ~[classes/:na]

It has started to work when I changed your code to this:
#RequestMapping("/tcp/test")
public String test(#RequestBody String name) {
Pay attention to the #RequestBody on the method param. By default Spring MVC does not know to what from the request to map into an argument for this param. So, it is left as null.
On the other hand, when the argument for that gateway call is null, Spring Integration cannot create a Message<?> to send because the payload cannot be null. Therefore you end up with such an exception.
We probably may revise that exception message to make it more obvious for end-users what is going on. Feel free to raise a GH issue on the matter!

Related

Camel & CXF & REST: ERROR No message body writer has been found for class java.util.ArrayList, ContentType: application/json

In my Spring configuration file:
<bean id="jacksonJsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean id="restJacksonProviderList" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="jacksonJsonProvider"/>
</list>
</constructor-arg>
</bean>
//......
<route id="RestMyRoute">
<from id="RestRequest" uri="cxfrs:/rest/MyService?resourceClasses=com.myself.services.MyService&bindingStyle=SimpleConsumer&providers=#restJacksonProviderList" />
<to uri="direct:doRoute" />
</route>
The Service interface:
#GET
#Path("/my/something/{id}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#WebMethod
#WebResult(name = "getSomethingResponse")
public List<MySomething> getSomething(
#PathParam("id") #WebParam(name = "id") String id);
The code above works! I can send the get request to the URl and I get a JSON response.
Now, I do a small change: Instead of defining the web service's URL (and the route) by XML configuration, I define them by Java code:
public class MyRoute extends RouteBuilder {
private String uriRest = "cxfrs:/rest/MyService?resourceClasses=com.myself.services.MyService&bindingStyle=SimpleConsumer&providers=#restJacksonProviderList";
#Override
public void configure() throws Exception {
from(uriRest).
to("log:input").
to("direct:doRoute").
to("log:output");
}
}
When I hit the web service URL, I am getting 500 Internal Server Error and in the logs (Tomcat) I see JAXRSUtils ERROR No message body writer has been found for class java.util.ArrayList, ContentType: application/json
Actually the debugger tells me that defining the URI by Java code is recognized, since I do hit the code inside the route.
I saw this error in many answers here, basically they say to add a Json provider and assign it to the CXF endpoint.
Seems to me like it is what I have done. But it does not work.
Any idea what I am doing wrong here?
As peeskillet said, it's because there isn't a list of providers registered under the name restJacksonProviderList. You can get the JndiContext like this and bind a list to it in the configure method of your routebuilder:
JndiContext registry = (JndiRegistry) context.getRegistry();
registry.bind("restJacksonProviderList", Arrays.asList(new JacksonJsonProvider()));
Edit after comments:
Change & for & in your cxfrs uri definition, & is only needed in xml.

Unable to get Session in Spring Controller when using Websockets

I am using Websockets SockJS with Spring MVC Framework. I tried the Stock Ticker example that's working fine but now I want to get Session in my Controller but I am unable to find a way out.
Client Code:
$scope.socket = new SockJS("ws/ws");
$scope.stompClient = Stomp.over($scope.socket);
$scope.stompClient.connect("guest", "guest",connectCallback, errorCallback);
//in connectCallback
$scope.stompClient.subscribe('/topic/agent-sendstatus', showScreenPop);
Java Code:
#MessageMapping("/topic/agent-sendstatus")
public void testmethod()
{
//How do i get Session here to further implement solution?
template.convertAndSend("/topic/agent-sendstatus","bcd");
}
Please suggest.
In case you are referring to the WebSocket session, Spring 4.1 lets you get the session attributes in a header of the incoming client messages which can be accessed via the SimpMessageHeaderAccessor.
#MessageMapping("/topic/agent-sendstatus")
public void testmethod(SimpMessageHeaderAccessor headerAccessor) {
String sessionId = headerAccessor.getSessionId(); // Session ID
Map<String, Object> attrs = headerAccessor.getSessionAttributes(); // Session Attributes
...
}
I also think you need a interceptor, you will get empty sessionAttributes without it.
You need to add HttpSessionHandshakeInterceptor in the dispatcher-servlet.xml:
<websocket:message-broker
application-destination-prefix="/app"
user-destination-prefix="/user">
<websocket:stomp-endpoint path="/websocket">
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs session-cookie-needed="true" />
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic, /message" />
</websocket:message-broker>
And then you will be able to get session in the controller:
#MessageMapping("/authorization.action")
public Message authorizationAction(
SimpMessageHeaderAccessor headerAccessor, Message message) {
Map<String, Object> sessionAttributes = headerAccessor.getSessionAttributes();
System.out.println(sessionAttributes);
// Do something with session
return new Message(...);
}

Camel: forward message to dynamic destinations (from database)

I am using camel 2.8.4 in my app. my app will receive request from a queue, then the request will be validated by a Validator. Base on the content of the message, the Validator will forward the request to different destinations. Validator will be a POJO bean. Destinations will be get from database (this is a MUST). I prefer to use spring dsl for camelContext.
1. I dont know how to write the validator to forward req to destinations.
2. Can we use something similar like this
<to uri='method=getURI() bean='Validator''> in camelContext
<camelContext>
<route id="route-1">
<from uri="mq:queue:QUEUE"/>
<bean ref="Validator" method="validate"/>
<!--i would be great if we can use <to uri="dynamicURI-from-database"> here -->
</route>
</camelContext>
Class Validator{
public void validate(String req){
if (...)
//get uri1 from database
String uri1=getURI(..);
//forward req to uri1
...........
else
//get uri2 from database
String uri2=getURI(...);
//forward req to uri2
...........
}
public String getURI(..){
......
return uri;
}
}
Use the dynamic URI feature to generate a URI at runtime. You can invoke a processor which sets the URI in exchange and then use that in the to clause.
Something like :
process(new Procesor()
public void process(Exchange exchange){
exchange.setHeader("myURI",someURI);
});
and in the to clause
<to uri="${header.myURI}"/>
Did you have a look at the dynamic recipient list pattern: http://camel.apache.org/recipient-list.html ?
You can use toD provided the destination endpoints are Http APIs. Please refer the link : https://camel.apache.org/components/latest/eips/toD-eip.html

GWT does not work with Spring REST service

I wrote a Spring REST application. I tested it with curl command and it worked truly.
In another GWT Ajax application I have an RequestBuilder object that it does not work with my Spring Rest: after calling sendRequest method, the event onResponseReceived is fired but the getText method returns an empty string.
this is a part of my spring servlet.xml configuration file
<bean id="jsonmembertemplate"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" >
<property name="contentType" value="text/javascript;charset=UTF-8"/>
<property name="disableCaching" value="false"/>
</bean>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
and a part of my controller class
#RequestMapping(method = RequestMethod.GET, value="/member/get/{memberid}")
public String getMember(Model model, #PathVariable("memberid") int id, HttpServletResponse response) {
model.addAttribute("member", memberDao.get(id));
return "jsonmembertemplate";
}
and gwt code
private RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, "http://localhost:8080/depna-nat-server/member/get/1?");
try {
rb.setHeader("Content-Type", "text/javascript;charset=UTF-8");
rb.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
Window.alert(Integer.toString(response.getStatusCode()));
Window.alert(response.getStatusText());
Window.alert(Integer.toString(response.getText().length()));
area.setText(response.getText());
}
#Override
public void onError(Request request, Throwable exception) {
Window.alert("fail");
}
});
} catch (RequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I have a couple of gwt applications working with json and xml rest services offered by spring, we use spring instead of gwt (rpc or rf) because these services are offered to 3party apps as well.
I started my first project with RequestBuilder and we dind't have any problem, so maybe you have some issue in your code, could you inspect the traffic and post the errors you have?
If you are running a cross-domain issue (statusCode=0 normally means it) , add a filter to your servlet container, take a look to this document.
I finally opted to use gwtquery-ajax and gquery-data-binding because it made really easy to consume these services and to map them to java objects.

Apache HttpClient making multipart POST to Spring #Controller class

It seems like there are several posts such as here asking how to use Apache Commons HTTPClient libraries in Java to do a POST to a Servlet. However, it seems like I'm having some problems doing the same thing with a annotated Spring controller method. I've tried a few things but gotten HTTP 401 Bad Request responses from the server. Any examples of doing this would be greatly appreciated.
EDIT: Code I am trying to use:
//Server Side (Java)
#RequestMapping(value = "/create", method = RequestMethod.POST)
public void createDocument(#RequestParam("userId") String userId,
#RequestParam("file") MultipartFile file, HttpServletResponse response) {
// Do some stuff
}
//Client Side (Groovy)
void processJob(InputStream stream, String remoteAddress) {
HttpClient httpclient = new DefaultHttpClient()
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1)
HttpPost httppost = new HttpPost("http://someurl/rest/create")
MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
InputStreamBody uploadFilePart = new InputStreamBody(stream, 'application/octet-stream', 'test.file')
mpEntity.addPart('file', uploadFilePart)
mpEntity.addPart('userId', new StringBody('testUser'))
httppost.setEntity(mpEntity)
HttpResponse response = httpclient.execute(httppost);
println(response.statusLine)
}
Still getting 400 Bad Request in the response from the server.
I hate to answer my own question when it shows incompetence, but it turns out the code was fine, this particular controller did not have a CommonsMultipartResolver defined in its servlet-context.xml file (multiple DispatcherServlets...long story :()
Here's what I added to make it work:
<!-- ========================= Resolver DEFINITIONS ========================= -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="50000000"/>
</bean>
Here is an example from the Spring Reference:
#Controller
public class FileUpoadController {
#RequestMapping(value = "/form", method = RequestMethod.POST)
public String handleFormUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
} else {
return "redirect:uploadFailure";
}
}
}

Resources