Callback between EJBs / local EJB calls - interface

Can you register EJB A as callback in an MDB B?
B.register(Aref)
in B: A.callback()
What would be Aref if the EJBs use local calls?
SessionContext.getEJBLocalObject()?

What you ask is not really possible in the proposed way.
If B is a Message Driven Bean, then it's never possible to call a method on it. In the messaging paradigm, the type of the receiver of a message is unknown. You thus can't reference an instance of the MDB. Instead, you post messages to a queue or topic and if your MDB is configured to listen to that its onMessage() method will be invoked.
Secondly, in EJB you don't often pass references around like in your example code. What kind of EJB bean is A supposed to be? A stateless session bean, or a stateful session bean?
In case it's a stateless session bean, the instance might not matter and you can probably just inject it:
#MessageDriven
public class NSMessageDrivenBean implements MessageListener {
#EJB
private A yourABean;
public void onMessage(Message message) {
// process message and then call A
yourABean.someMethod();
}
}
If the callback needs to be done to a type that is unknown in advance (depending on the message being send), then one mechanism for this is via a JMS reply.
In the message being send to the message driven bean, you then include code like this:
message.setJMSReplyTo(someDestination);
message.setJMSCorrelationID(someCorrelationID);
someDestination represents your callback, it's a destination to which something is listening, and this something can then invoke the call on the stateless session bean (in the context of the client).
E.g. something like:
connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(someDestination).setMessageListener(
new MessageListener() {
#Override
public void onMessage(Message message) {
yourABean.someMethod();
}
}
In this case, someDestination can be a temporary destination.

Related

How to convert the Core message to a JMS message?

I need to convert org.apache.activemq.artemis.core.message.impl.CoreMessage to javax.jms.Message. How can i do this? Maybe there is a required util method somewhere in the code, or it needs to be done manually?
I want to intercept the following events:
afterSend
afterDeliver
messageExpired
And then send the message to a direct endpoint Camel route which requires a javax.jms.Message instance.
My recommendation would be to simply copy the message and route the copy to the address of your choice, e.g.:
public class MyPlugin implements ActiveMQServerMessagePlugin {
ActiveMQServer server;
#Override
public void registered(ActiveMQServer server) {
this.server = server;
}
#Override
public void afterSend(ServerSession session,
Transaction tx,
Message message,
boolean direct,
boolean noAutoCreateQueue,
RoutingStatus result) throws ActiveMQException {
Message copy = message.copy();
copy.setAddress("foo");
try {
server.getPostOffice().route(copy, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Then a Camel consumer can pick up the message and do whatever it needs to with it. This approach has a few advantages:
It's simple. It would technically be possible to convert the org.apache.activemq.artemis.api.core.Message instance into a javax.jms.Message instance, but it's not going to be straight-forward. javax.jms.Message is a JMS client class. It's not used on the server anywhere so there is no existing facility to do any kind of conversion to/from it.
It's fast. If you use a javax.jms.Message you'd also have to use a JMS client to send it and that would mean creating and managing JMS resources like a javax.jms.Connection and a javax.jms.Session. This is not really something you want to be doing in a broker plugin as it will add a fair amount of latency. The method shown here uses the broker's own internal API to deal with the message. No client resources are necessary.
It's asynchronous. By sending the message and letting Camel pick it up later you don't have to wait on Camel at all which reduces the latency added by the plugin.
org.apache.activemq.artemis.jms.client.ActiveMQMessage
This looks like the implementation of javax.jms.Message with an underlying org.apache.activemq.artemis.api.core.client.ClientMessage which extends CoreMessage

Create Spring Boot RestController dynamically

I need to create a Rest endpoint dynamically in my Spring Boot application. Instead of statically creating the class with #RestController, is there a way to instantiate and activate a Rest service at runtime? It should be possible to specify the endpoint, input parameters etc at runtime.
Are there some Groovy options too?
Thanks,
Sandeep Joseph
I think the approach to take would be to create a custom MvcEndpoint that will handle all requests on a specific path, from there depending on your internal configuration you can process requests. It's basically just a Servlet (that's also an option). You're fully in control of the request.
public class MyEndpoint extends AbstractMvcEndpoint
// can optionally implements ApplicationContextAware, ServletContextAware
// to inject configuration, etc.
{
#RequestMapping("/dynamic-enpoints-prefix/**")
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// here you have the request and response. Can do anything.
}
}

NullPointerException with #Inject and #PostPersist Method

After an entity is persisted, I want to execute a Bean, which sends a registration Mail to the newly registered user. I want to do this with a Listener class. I did the following:
Annotated the Entity with #EntityListener (UserListener.class)
Created the Listener and annotated it with #Stateless
Here is the code of the listener:
( the system.out.println part is just for testing purposes)
#Stateless
public class UserListener {
#Inject
private MailSenderController mailSenderController;
#PostPersist
void onPostPersist(User user) throws AddressException{
System.out.println("PostPersist");
System.out.println("Username: " + user.getUsername());
mailSenderController.sendRegistrationMail(user);
}
}
The MailSenderController is a #RequestScoped annotated Bean.
If I execute the code, I get a NullPointerException.
If I remove mailSenderController.sendRegistrationMail(user), the code works fine.
I think the onPostPersist gets executed before the MailSenderController gets injected and this causes the NullPointerException.
Can someone help me out with this problem?
I am guessing that MailSenderController is not the entry point of your user registration entry point. If yes then MailSenderController is always going to be NULL. Considering the MailSenderController has request scope, DI framework would only instantiate the controller processing HTTP request for sending mail.
From design point of view its not good to call your controller directly from DAO layer classes. I think you need to create a new managed bean (single instance) MailSenderService and then inject the new service instead of accessing a request scoped controller.
just add #Named annotation to MailSenderController

Delay start of JMS Listener (MDB) in JBoss 6.0

we have multiple instances of JBoss-Server in a clustered environment. For background tasks there is a global queue available, that manages all jobs registered at it. For this queue there is a simple listener (MDB) on each node, manages the incoming messages. This listener does a manual lookup (no injection) for a singleton bean and starts a pre defined method.
Everything works fine so far, but the method in the singleton bean uses some other (no singleton services) that are not available under some circumstances.
For example if a node will be restarted and there are left messages in the queue (not processed yet) the messages will be picked up by the listener and all further beans are null, so the job produces a NPE.
Is it possible to define a delay time in JMS-Listener after messages will be picked up or is it possible to define an "application completely deployed" hook in there? The DependsOn-Annotation does not work, because of the usage of non singletons.
A possibility can be to set the MDB-property "DeliveryActive" to false and start the bean after full deployment. Is there a simple, working way to do this programatically (not in jmx-console)? Any manuals for this I found, redirects me to a manual jndi lookup. I think it have to be possible to inject the Bean per annotation and call startDelivery()? Is there a good place to do this in application?
Another hint takes me to the initialise in order property in application.xml, because the problem might be connected to JBoss Deployment order (some EJBs will be later available than the listener), but there seems to be a bug in JBoss 6.0 and upgrading to 6.1. is not an option. Maybe there is a walkthrough for this?
I hope that the problem is well enough explained, otherwise please ask for further informations.
Thanks in advance,
Danny
Additional informations:
JBoss 6.0.0 Final
HornetQ 2.2.5 Final (already updated, because of the buggy default version of JBoss)
The Listener:
#MessageDriven(activationConfig =
{
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "/queue/SchedulerQueue")
})
public class SchedulerQueueListener implements MessageListener {
...
#Override
public void onMessage(Message message) {
...
service = (IScheduledWorkerService) new InitialContext().lookup(jndiName);
EJobResult eJobResult = service.executeJob(message);
...
}
A sample worker:
#Singleton
#LocalBinding(jndiBinding = SampleJobWorkerService.JNDI_NAME)
public class SampleJobWorkerService implements IScheduledWorkerService {
...
#EJB(name = "SampleEJB/local")
private ISampleEJB sampleEjb;
...
#Override
public EJobResult executeJob(Message message) {
int state = sampleEjb.doSomething(message.getLongProperty(A_PROPERTY));
}
In this case the sampleEjb - member will be null sometimes
As a workaround, instead of calling EJB's directly from MDB, you can create a timer with a timeout with some delay. Therefore there will be some delay in execution.
In Timer's timeout method, then you can call singleton EJB, which in case will call other non-singleton EJB's.
JBoss specific : Can try setting the property in the message object before sending.
msg.setLongProperty("JMS_JBOSS_SCHEDULED_DELIVERY", (current + delay));
Other alternative is _JBM_SCHED_DELIVERY.
Edit :
For 1st part, you can have JTA transaction, which may span across JMS & EJB. Therefore failover & other things may be handled accordingly.
You can also increase the redelivery delay for the message object.
<address-setting match="jms.queue.someQueue">
<redelivery-delay>5000</redelivery-delay>
</address-setting>
I am in the same trouble at the moment.
I propose you use EJB 3 startup bean annotation #Startup on your singleton bean to invoke the startDelivery method on your Message listeners.

Cancel GWT RequestFactory request

Is there a way to cancel/abort request factory requests? Using GWT 2.3
There is no way to cancel a request after the fire() method has been called. Consider building a custom Receiver base class such as the following:
public abstract class CancelableReceiver<V> extends Receiver<V> {
private boolean canceled;
public void cancel() {
canceled = true;
}
#Override
public final void onSuccess(V response) {
if (!canceled) {
doOnSuccess(response);
}
}
protected abstract void doOnSuccess(V response);
}
The pattern can be repeated for other methods in the Receiver type.
Another option would be to create an alternative com.google.web.bindery.requestfactory.shared.RequestTransport type, instead of using DefaultRequestTransport. Downside to this (and upside to BobV's approach) is that you won't know when in the request on the server you kill it, so it might have already run some of your methods - you won't get feedback from any of them, you'll just stop the outgoing request.
I suspect this is why RF doesn't have this feature already, as RPC does. Consider even the case of RPC though or RequestBuilder - how do those notify the server that they've changed their mind, and to not run the request? My understanding is that they don't - the only way they are shut down early is when they try to read/write to the response, and get a tcp error, as the connection has been closed. (It's possible I am mistaken, and that another thread keeps an eye on the state of the tcp connection and calls thread.stop(Throwable), but stop has been deprecated for quite a while.)
One thought would be to send a message to the server, telling it to kill off other requests from the same session - this would require active participation in your server code though, possibly made generic in a ServiceLayerDecorator subtype, probably in at least invoke, loadDomainObject(s), and getSetter, among others. This pretty clearly is to involved to ask GWT to build it for you though...