Liferay Message bus - liferay

I want to create a custom message listener which also sends back response, I'm implementing MessageListener , but it has only void type method
public void receive(Message arg0) throws MessageListenerException
I was trying to do
arg0.setResponse("Test");
but it resulted in an exception.

MessageListener is purposeds only for listening of messages without responsing. For response you can use again MessageProducer.

Related

What does #serviceactivator does exactlly?

I wish to understand what does serviceactivator annotation do? Because I want to modify message when I got it through serviceactivator. For example I have seen, there is no message parameter I can control. Why handle can receive message, even I cannot see any message parameter passed in, what is the principle?
#Bean
#ServiceActivator(inputChannel="requests")
public MessageHandler jmsMessageHandler((ActiveMQConnectionFactory connectionFactory) {
JmsSendingMessageHandler handler = new JmsSendingMessageHandler(new
JmsTemplate(connectionFactory));
handler.setDestinationName("requests");
return handler;
}
I wish I can do
#Bean
#ServiceActivator(inputChannel="requests")
public MessageHandler jmsMessageHandler(Message message) {
String new_message = message.split();
}
The #ServiceActivator wraps a call to the consumer endpoint. In case of MessageHandler it is used as is and the message from the inputChannel is passed to it. But if your code is not based on the MessageHandler, but is a simple POJO method invocation, then everything is based on the signature of your method. In the end that POJO method call is wrapped to the MethodInvokingMessageHandler.
In your case it must be something like this:
#ServiceActivator(inputChannel="requests", outputChannel="toJms")
public String jmsMessageHandler(Message message) {
return message.split();
}
So, no #Bean, because we deal only with POJO method invocation. The message is something incoming from request message and return String is going to become a payload from output message to processed somewhere downstream on the toJms channel.
See more info in the Reference Manual: https://docs.spring.io/spring-integration/docs/current/reference/html/#annotations

Webapi 2 global exception handling not raised

I'm uising web api 2 to develop services for a client, to manage errors we are using a ExceptionsFilterAttribute, but as you know, in this level not all exception are catched.
Some errors are raised in protected void Application_AuthenticateRequest(Object sender, EventArgs e) and I want to handle them and send a custom message to our client to give him more details about the error, to solve this I create a GlobalExceptionHandler
public class GlobalExceptionHandler: ExceptionHandler
{
//A basic DTO to return back to the caller with data about the error
private class ErrorInformation
{
public string Message { get; set; }
public DateTime ErrorDate { get; set; }
}
public override void Handle(ExceptionHandlerContext context)
{
//Return a DTO representing what happened
context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,
new ErrorInformation { Message="We apologize but an unexpected error occured. Please try again later.", ErrorDate=DateTime.UtcNow }));
//This is commented out, but could also serve the purpose if you wanted to only return some text directly, rather than JSON that the front end will bind to.
//context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError, "We apologize but an unexpected error occured. Please try again later."));
}
}
In WebApiConfig i added this line :
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
The the Application_AuthenticateRequest raise some errors but GlobalExceptionHandler is never reached.
Do you have any idea how can I solve this issue ?
Thanks in advance.
Application_AuthenticateRequest does not come in the Web API pipeline. So if an exception is thrown in this method those can be caught by the Web API exception handler, because the exception is thrown before the Web API pipeline is started.
There are two ways to do this:
Either change the authentication mechanism and use Web API Authentication(IAuthenticationFilter) instead of Application_AuthenticateRequest.
If this project has only Web API related controllers, not like MVC and all.
Or use Application_Error in the Global.asax.cs file to catch the exception thrown in Application_AuthenticateRequest

MessageTemplate cause no converter found exception in MVC controller?

related question
I am sending message from REST API to SI message channel, which delegate to a sending message adapter. The message adapter send a message to TCP client. nothing needs to be return/response. My TCP client successfully received the message but the MVC controller throw an exception
Controller code
#Autowired
MessageChannel invokeChannel;
#RequestMapping(value="/invoke/{payload}")
public ResponseEntity<String> sayHello(#PathVariable String payload)
{
//trigger gateway to send a message
MessagingTemplate template = new MessagingTemplate();
template.send(invokeChannel, new GenericMessage<String>(payload));
return new ResponseEntity<String>(payload, HttpStatus.OK);
}
The Exception
java.lang.IllegalArgumentException: No converter found for return
value of type: class java.lang.String
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:178)
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
I couldn't find where and what is causing this. my breakpoint at return new ResponseEntity(...) is not reached.
my webmvcconfig
#EnableWebMvc
#Configuration
#ComponentScan({ "helloworldmvc" })
public class WebappConfig extends WebMvcConfigurerAdapter {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
converters.add(new MongoMessageConverter());
}
}
//trigger gateway to send a message
You should be sure that your flow for the template.send(invokeChannel) is really one-way. No one gateway may wait for rely there. That is for your comment like:
my breakpoint at return new ResponseEntity(...) is not reached.
If you can't reach that row of code, try to debug exactly that AbstractMessageConverterMethodProces. And there is need to figure out why producibleMediaTypes after the code:
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, clazz, type);
if (value != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + clazz);
}
is empty. Maybe you request uses some Accept non-compatible with the String? Or your WebMvcConfigurer overrides List<HttpMessageConverter<?>> converters somehow without any String-awere converter?
Error message:
No converter found for return value of type: class java.lang.String
It says that the MVC doesn't know which converter use to return the REST response from this service. to use the default converter which are available in spring.
Please add an annotation #ResposeBody in the method signature.

How to save all FacesMessages over different requests

I was just wondering to implement a kind of log display to user where in all messages in the application are displayed to user all the time.
Since I use JSF 1.2 and RF 3.3.3, wanted to know if it is possible to save all messages be it added by different requests and display them to user, so that user will know the history of actions he has done. It is also useful for support team to analyse the cause of the problem and he can send the messages to developer if it needs to simulated or to debug purpose also.
I also know facesmessages get cleared over different requests, thats where my question lies, to save messages over different requests :)
Could be handled in different ways by saving them is a session variable or so...I would appreciate all possible answers
You could collect all messages during the render response in a PhaseListener. E.g.
public class MessagesListener implements PhaseListener {
#Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
#Override
public void beforePhase(PhaseEvent event) {
FacesContext context = event.getFacesContext();
Iterator<String> clientIds = context.getClientIdsWithMessages();
while (clientIds.hasNext()) {
String clientId = clientIds.next();
Iterator<FacesMessage> messages = context.getMessages(clientId);
while (messages.hasNext()) {
FacesMessage message = messages.next();
save(clientId, message); // Do your job here.
}
}
}
#Override
public void afterPhase(PhaseEvent event) {
// NOOP.
}
}
To get it to run, register it as follows in faces-config.xml:
<lifecycle>
<phase-listener>com.example.MessagesListener</phase-listener>
</lifecycle>

Hub.Clients.User(userId).methodCall always throws Object reference not set to an instance of an object

I have a NotificationHub class which inherits from the Hub class.
public class NotificationHub : Hub
{
public void Send(string userId, Notification notification)
{
Clients.User(userId)
.notificationReceived(notification);
}
}
This always fails with
[NullReferenceException: Object reference not set to an instance of an object.]
Microsoft.AspNet.SignalR.Hubs.SignalProxy.Invoke(String method, Object[] args) +88
Microsoft.AspNet.SignalR.Hubs.SignalProxy.TryInvokeMember(InvokeMemberBinder binder, Object[] args, Object& result) +12
CallSite.Target(Closure , CallSite , Object , <>f__AnonymousType0`4 ) +351
However if I do this:
public class NotificationHub : Hub
{
public void Send(string userId, Notification notification)
{
var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
context.Clients.User(userId)
.notificationReceived(notification);
}
}
It works .... what gives here? Most of the examples I've seen do not require getting the context explicitly, should it not already be available from Hub? I would rather not have to grab it explicitly every time.
Here is my IoC Setup:
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new SimpleInjectorHubActivator(container));
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => new SignalRHubUserIdProvider());
Activator:
public class SimpleInjectorHubActivator : IHubActivator
{
private readonly Container _container;
public SimpleInjectorHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return (IHub) _container.GetInstance(descriptor.HubType);
}
}
If you want to send something to clients from outside of hub handler methods (ie not during handling message on server), you have to use GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
Reason is that when the method is called to handle some client side message, hub instance is created by SignalR and Clients property is correctly initialized. This is not the case when you calling method yourself from server code (and probably creating hub instance yourself).
Imho error message is not very clear and this use case should be handled better by SignalR. Anyway for the same reason i suggest to separate all the methods sending messages to clients which are intended to be called from server code to different class (not derived from Hub).

Resources