How to access a static injected dependency on Play2 application exit - java

I have a Play 2 application which is using Guice to inject a static object (a realtime sensor monitoring object) into Application.java:
controllers.Application:
public class Application extends Controller {
#Inject static MonitorService monitorService;
...
}
module.Dependencies:
public class Dependencies {
....
#Provides
#Singleton
public MonitorService getMonitorService(final MonitorFactory factory) {
return new MonitorService(factory){
#Override
public MonitorService(Factory factory){
return factory.getMonitor();
}
}
}
}
My problem is that I would like to access the factory or monitor object when the play application is exiting in order to shut it down gracefully. I have looked at hooking into the GlobalSettings.onStop but cannot see a way to extract a reference from the Play.Application object. I have tried injecting MonitorService into the Global class but it returns a null object so I am assuming the Dependencies object has been destroyed by this stage.
I am also aware this approach may be totally wrong ;)
Any help is greatly appreciated.

I assume that you are using the Typesafe plugin.
AFAIK, unfortunately, there is no listener when the plugin is shut down, there is an onStart() method, but not any onStop() method.
So either you fork the plugin, either you integrate Guice yourself in the onStart/onStop methods of the Global object.

Related

Is there any ways to intercept a Runnable using AOP

Here is my problem.
I have a class implements Runnable, and it is a daemon thread, which will be permanently alive during the application lifecycle.
Now I want to perform a function just like AOP enhancement to enhance this Runnable class.
It was quite easy to have that pointcut if the class is annotated with #Service or #Component. But now it is a class implememts the Runnable interface so I have not yet find any possible ways to do so without any intrusion to the original code.
Here below is my testing code:
this is the parent interface of my daemon thread
public interface MessageRunnable extends Runnable {
void doConsume();
}
one of the working thread:
#Slf4j
public class MyDaemonThread implements MessageRunnable{
#Override
public void run() {
log.info("now in run function,ready to call doConsume...");
while(true){
log.info("I m still alive...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
doConsume();
}
}
#Override
public void doConsume() {
log.info("doConsume was called...");
}
}
And here is the simple test:
#Component
public class TestComponent {
private MyDaemonThread testThread;
#PostConstruct
public void init(){
if(testThread==null){
testThread=new MyDaemonThread();
new Thread(testThread).start();
}
}
}
After running the application.
I can see the log is printing well, but now if I want to add a function to print now I'm in the aspect method before the doConsume function was invoked, I don't have any idea to do so without any intrude to my source code, it is acceptable to add codes ,but no modifications were allowed at all.
I wonder if there is any possible ways to let spring handle this daemon thread, then it is easy to do an aspect point cut. Otherwise, I have to change the code to add a proxy method and an interceptor do achieve the goal....
First of all , MyDaemonThread instance is not a spring container managed bean. The code uses new keyword to create the instance. Spring AOP can only advise a spring bean.
Even if the MyDaemonThread is made a spring bean , it is not possible to advise doConsume() using Spring AOP with the current code ( OP mentions no modifications are allowed ).
From the reference documentation
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are, by definition, not intercepted.

Dependency injection issue in Apache Ignite cache event listener and EJB

I have a Startup+Singleton EJB in which I need to inject an object. In the PostConstruct method of this EJB, I need to register a remote cache event listener for an Ignite grid. The "apply" method of this listeners should call a method of the injected object.
#Startup
#Singleton
public class RegisterEventListeners {
#Inject
private EventListenerDelegate listenerDelegate;
#PostConstruct
public void registerListeners() {
Ignition.setClientMode(true);
Ignite ignite = Ignition.start("ignite-config.xml");
registerRemoteEventListener(ignite);
}
public void registerRemoteEventListener(final Ignite ignite) {
IgnitePredicate<CacheEvent> remoteListener = new IgnitePredicate<CacheEvent>() {
public boolean apply(CacheEvent e) {
listenerDelegate.respondToCacheEvent(ignite, e);
return ignite.affinity("IgniteCache").isPrimary(ignite.culster().localNode(), e.key());
}
};
ignite.events(ignite.cluster().forCacheNodes("IgniteCache")).remoteListen(null, remoteListener, EventType.EVT_CACHE_OBJECT_PUT);
}
}
In the EventListenerDelegate class, I am further injecting something else which will eventually do something with the retrieved cache event. The reason I am passing the Ignite object also to the respondToCacheEvent method of this class, is because I am issuing a cache.remove within this method. So its easy to quickly get a handle for the cache if I pass the Ignite object itself. Hope that is not a problem.
This deploys just fine. But when I put something on the cache, I get a NullPointerException on the "listenerDelegate.respondToCacheEvent" line in the "apply" method. This clearly means that when Ignite did the registration of the listener, the CDI injection had not happened by that time. Or may be the problem is something else entirely.
Is what I am doing correct? How else can I ensure that all injects happen properly and then the remoteListener is registered?
Well, turns out I need default constructors for classes whose objects I want to be injected in other classes :(
I did not know that. After adding empty no-arg constructors for my EventListenerDelegate class, all is well!
Sorry for wasting your time :(
remoteListener is serialized and sent to remote nodes when Ignite event listener is registered. So listenerDelegate has to be injected before registerRemoteEventListener method is called, but it looks like it's null at that moment.
Can you check if this the case?

How to use injection in Test NG test listener

I have a Test NG listener class, that is invoked every time a test fails:
public class MyListener implements ITestListener {
#Inject
private MyBean myBean;
#Override
public void onTestFailure(ITestResult result) {
myBean.logDetails();
// log certain information about the failure,
// using the injected object.
}
}
When a test fails, the method is called, this part works fine.
The problem is the object isn't injected - it's just null. I have checked everything, and the usual conditions for CDI working are all ok.
The class has an empty constructor, and I am not calling new() on it anywhere.
Is there any way to get the object injected?
I have looked at this question but I can't see how to do CDI in the test listener.
I've also tried annotating the listener class as a TestNG test, and also making the listener a subclass of a guice factory class, but no luck and I'm a bit lost as to how to do it.
Thanks!
Currently, TestNG doesn't allow injection (with Guice) in listeners and it doesn't provide hook on listener creation (TestNG is calling new on listener itself).
https://github.com/cbeust/testng/issues/279
But if you run TestNG with code, you may ask an instance to your injection framework and provide it to TestNG.
Using one of the replies of the previously linked github issue (thanks #juherr) here the TestNG 7.4.0 answer, without #Inject but working nonetheless.
To use the baked in Guice dependency injection container from a listener, you need to get the instance of the Injector from the suite in this way:
#Override
public void onTestFailure(ITestResult result) {
final Injector parentInjector = result.getTestContext().getSuite().getParentInjector();
final YourGuiceModule module = parentInjector.getInstance(YourGuiceModule.class);
final MyBean myBean = parentInjector.createChildInjector(module).getInstance(MyBean.class);
myBean.logDetails();
}
For this to work, you need to make sure that every test running this listener have YourGuiceModule and MyBean should be provided by that forementioned module.
The exact answer to your question will be possible to solve in version 7.5.0, but still only if you use Guice.
Here a utility method i've created in Kotlin to provide any instance:
private fun <T> ISuite.getInstanceOf(clazz: Class<T>): T =
with(this.parentInjector) {
getInstance(YourModule::class.java)
.let {
createChildInjector(it)
.getInstance(clazz)
}
}
Opinion: i prefer (and suggest) to have a compile-time check for dependency injection provided objects: In another solution, I've solved this by using dagger and by ditching completely the testng dependency injection provider.

Guice and non-Singleton Servlets

How we can use non-Singleton servlet or handler in Guice, for example I want to create new instance for every request and immediately destroy it or give it to garbage collector after processing the request.
I dont want to keep ii in memory as singleton or reuse for other future requests.
I think probably somehow by using bind() function,
RGDS
You want to use RequestScope.
I typically use provider methods with scopes, so you would have code that looks like
public class FooModule extends AbstractModule {
#Override protected void configure() {
// set up bindings
}
#Provides
#RequestScoped
PerRequestObject providePerRequestObject() {
return new PerRequestObject(...);
}
}
Be sure to install ServletModule and setup the GuiceFilter or else this won't work!
Have you tried #SessionScoped?

Spring IoC - Ensuring all beans are created before #PostConstruct/afterProperiesSet

I've got a project using Spring IoC for dependency injection, and I'm trying to slightly simplify my model by having one central location for accessing most of my beans.
I'm running into a problem using the #PostConstruct mechanism, or alternatively when implementing the InitializingBean interface. While all the dependencies in that particular bean may have been resolved, the dependencies in injected beans may not have been. For example I have:
public class A {
public void doSomething() {};
}
public class B {
private A objectA;
#Required
public void setObjectA(A objectA) {
this.objectA = objectA;
}
public A getObjectA() {
return objectA;
}
}
public class C implements InitializingBean {
private B objectB;
#Required
public void setObjectB(B objectB) {
this.objectB = objectB;
}
public void afterPropertiesSet() throws Exception {
objectB.getObjectA().doSomething();
}
}
My context.xml file defines these three beans and injects the appropriate properties, but I get a NullPointerException when the object of class C gets instantiated and the afterPropertiesSet method is called, debugging shows me that the call to getObjectA() returns null. If I inject object A directly into class C I get no errors.
Is there a mechanism I can use to ensure that all beans have been completely instantiated before my afterPropertiesSet method / any method annotated with #PostConstruct is called?
Thanks,
Joseph.
The afterPropertiesSet() is little too early to call methods on injected dependencies. Indeed, the init-method (if you have that in XML) is called after afterPropertiesSet() and then postProcessAfterInitialization() of BeanPostProcessors are called. You have #Required annotation and so, ofcourse, RequiredAnnotationBeanPostProcessor is executed.
Lifecycle callback methods are what they are: they inform you about lifecycle events and their purpose is not to enable you to hijack the task that Spring is performing. (Though you can do it as you did when directly injecting object A in C- but it is not recommended).
If you want to use object A (or any other spring bean for that matter) in class C, then I would recommend to use ApplicationContextAware (or BeanFactoryAware as the case may be) and use getBean() method to get fully baked and ready to serve bean!
Implement ApplicationListener[ContextRefreshedEvent] and do your work in onApplicationEvent(). Word of caution - ContextRefreshedEvent is sometimes published multiple times, so you may want to set a flag after the first time you get it to ignore the additional events.
Use #DependsOn to ensure that A is instantiated before C.

Categories