Scheduled Tasks in Liferay with Autowired - spring

im trying to create scheduled task in liferay portlet.
Liferay: 6.2
Spring: 3.1.4.RELEASE
With
<scheduler-entry>
<scheduler-description>test-scheduler</scheduler-description>
<scheduler-event-listener-class>
project.ScheduledProcesser
</scheduler-event-listener-class>
<trigger>
<simple>
<simple-trigger-value>
1
</simple-trigger-value>
<time-unit>minute</time-unit>
</simple>
</trigger>
</scheduler-entry>
and the corrensponding class
#Component
public class ScheduledProcesser implements MessageListener {
private static Log log = LogFactoryUtil
.getLog(ScheduledProcesser.class);
#Autowired
#Qualifier("myRequestService")
private RequestService service;
#Override
public void receive(Message message) throws MessageListenerException {
log.info("Starting");
Request req = service.get("AAA746");
if (req!=null)
log.info("REQ -" + req.getId());
log.info("Finished");
}
The method is firing. But the service component is null. Normally is the service in other parts working well.
I have tried to find the solution, but maybe there is some settings missing.
Thanx,

MessageListener is not instantiated by Spring, but by Liferay (see the implementation of QuartzSchedulerEngine.getMessageListener(String, ClassLoader)). And Liferay just instantiates the class. So you can't autowire anything into a MessageListener that is defined in the liferay-portlet.xml.
But you could use PortalBeanLocatorUtil.locate instead, if your service is defined in the portal application context.

Related

What is the best way to inject a singleton service into a JAX-RS/Jersey resource?

For example, what if several resource endpoints need access to some message bus to handle requests? Surely there is some way to register a singleton service class and inject it into the resources when the service class itself is NOT a resource but used by the resources.
All of the examples I've seen with providers or custom HK2 bindings refer to resources.
The closest thing I found to what I'm looking for was with this question:
Trouble creating a simple singleton class in Jersey 2 using built-in Jersey dependency injection
What is the best JAX-RS/Jersey way of doing this?
Note that the programmatic way would be most useful, I'm not using an xml file to configure the server.
If your platform supports EJB, you could use the #Singleton EJB (javax.ejb package, not javax.inject), and inject it on your resources with the #EJB annotation. Singleton EJB have also outofthebox concurrency access control.
On plain Jersey, you can use CDI application context. Declare the service class with an #ApplicationScoped annotation and inject it on your resources with #Inject. CDI will only instantiate one bean.
If you cannot annotate the service class, you can create a method that provides your service implementation an annotate it with #Produces and #ApplicationScoped.
#Produces
#ApplicationScoped
public MyService produceService() {
// instantiate your service client
}
And then use it on your resources, with:
#Inject
private MyService
Answer credit goes to #areus the answer provided here.
However, I'm providing my own answer so that I can share the code.
The Service Bean
#Singleton
public final class MyServiceBean
{
private static final AtomicInteger INSTANCES = new AtomicInteger();
private final AtomicInteger calls = new AtomicInteger();
public MyServiceBean()
{
INSTANCES.incrementAndGet();
}
public String getMessage()
{
return String.format("MyServiceBean{INSTANCES=%d, CALLED=%d}", INSTANCES.get(), calls.incrementAndGet());
}
}
The Resource Class
#Path("/messages")
public final class MyResource
{
#Inject
private MyServiceBean bean;
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response handle()
{
return Response.ok(this.bean.getMessage())
.type(MediaType.TEXT_PLAIN_TYPE)
.build();
}
}
HK2 Binder
public final class MyServiceBeanBinder extends AbstractBinder
{
#Override
protected void configure()
{
bind(MyServiceBean.class).to(MyServiceBean.class).in(Singleton.class);
}
}
Then just register the binder and the resource like so:
final ResourceConfig config = new ResourceConfig();
config.register(MyResource.class);
config.register(new MyServiceBeanBinder());
Starting the server and hitting the resource multiple times yields:
MyServiceBean{INSTANCES=1, CALLED=1}
MyServiceBean{INSTANCES=1, CALLED=2}
MyServiceBean{INSTANCES=1, CALLED=3}
MyServiceBean{INSTANCES=1, CALLED=4}
MyServiceBean{INSTANCES=1, CALLED=5}

How to use application.properties in org.quartz.Job Class

I have created a spring boot application to implement Quartz scheduler. In Job class, I want to use some property from application.properties. How to inject that?
I have tried below but getting null:
#Component
public class ScheduleJob implements org.quartz.Job {
private static final Logger LOGGER = LogManager.getLogger(ScheduleJob.class);
public ScheduleJob() {
}
#Value("${ijobs.service.url}")
private String ijobsUrl;
public void execute(JobExecutionContext context) throws JobExecutionException {
LOGGER.info("Job exceution starts--->");
System.out.println("-------------------"+ijobsUrl);
Spring requires annotating the class with #Component for it to manage it (including loading any properties into the class). If you use "new" to create the object, then it is outside Spring's control and it won't inject the dependencies/values into it.
On side note, there is native support for Quartz if using Spring Boot: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-quartz.html
Firstly, the ScheduleJob class should be annotated with #Component for spring to manage it. Secondly, if you want any property to be injected you could do it in a similar way to how you are injecting value of ijobsUrl.
put your required property in application.properties
#Value("${my.property}")
private String myProperty

push a dynamic message in Scheduler websocket using spring boot using stomp

I try to make a chatbot using springboot (websocket), i want to know if it's possible to push a dynamic message in Scheduler, and i need some help, i'can't fugure it out.
I want to push the message in the Scheduler Configure how could i do that:
#EnableScheduling
#Configuration
public class SchedulerConfig {
#Autowired
SimpMessagingTemplate template;
#Scheduled(fixedDelay = 3000)
public void sendAdhocMessages() {
template.convertAndSend("/topic/user", new UserResponse("Fixed Delay Scheduler"));
}
}
in the sendAdhocMessages method i want to pass a message that will be displayed in an html page. in the Official doc it's impossible to pass a parameter to a method which is annotated by #Scheduled, is there any methd to do that?
The official documentation contains a hint to, how you could pass values to the scheduled method. Maybe you could provide a bean that acts as a message provider. In the scheduler class you autowire the message provider and request the messages.
A short code example:
#Componet
public class MessageProvider {
private String message;
// getter and setter ...
}
In the scheduler you could use the message provider like following:
#EnableScheduling
#Configuration
public class SchedulerConfig {
#Autowired
SimpMessagingTemplate template;
#Autowired
MessageProvider messageProvider;
#Scheduled(fixedDelay = 3000)
public void sendAdhocMessages() {
String currentMessage = messageProvider.getMessage();
template.convertAndSend("/topic/user", new UserResponse(currentMessage));
}
}

How to use CDI into JAX-RS client

I have searched a while on SO and official documentation but I cannot found a way to use directly CDI injection into a JAX-RS client.
I retrieve a client using the builder method and I want to register a WriterInterceptor (or any filter like component) which uses injection to retrieve another bean.
I want to use CDI injection and avoid registering each bean with HK2.
ClientBuilder.newBuilder()
.register(MyWriter.class)
.build();
And MyWriter with the injected class.
#Provider
public class MyWriter implements WriterInterceptor {
private final MyRepo repo;
#Inject
public MyWriter(MyRepo repo) {
this.repo = repo;
}
#Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
context.proceed();
}
}
public class MyRepo {
}
I am running in an embedded jetty with Jersey 2 and Weld SE.
Its possible to inject in java se application using wield .
#Singleton
public class Application {
private static Logger logger = LoggerFactory.getLogger(Application.class);
#inject
private SomeOtherBean injectedBean;
public void run() {
logger.debug("application initialized");
injectedBean.doSomething();
}
}
inside main initialize weild
import java.io.IOException;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
public class EntryPoint {
public static void main(String[] args) throws IOException {
Weld weld = new Weld();
WeldContainer container = weld.initialize();
Application application = container.instance().select(Application.class).get();
application.run();
weld.shutdown();
}
}
Have a look at below doc
https://docs.jboss.org/weld/reference/latest/en-US/html/environments.html#_java_se
also below tutorial
https://randling.wordpress.com/2011/08/15/cdi-in-java-se/
If I understand everything correctly, this has already been asked and answered. In a nutshell: you have to override the default behaviour of the H2K Binder, so it reaches for the Weld Bean Manager. You don't have to register every Bean with H2K later on.
Edit: to contain everything in the post, so you don't have to read the comments:
The linked answer is for the server-side, not the client.
With standard tools (Jersey Client-side injection providers and the Weld bridge), it seems to be a too big overhead/impossible to do
Apparently in the Dropwizard project they managed to do custom client-side injection.

ClassBridge with DAO class injected

I have a Hibernate Search ClassBridge where I want to use #Inject to inject a Spring 4.1 managed DAO/Service class. I have annotated the ClassBridge with #Configurable. I noticed that Spring 4.2 adds some additional lifecycle methods that might do the trick, but I'm on Spring 4.1
The goal of this is to store a custom field into the index document based on a query result.
However, since the DAO, depends on the SessionFactory getting initialized, it doesn't get injected because it doesn't exist yet when the #Configurable bean gets processed.
Any suggestions on how to achieve this?
You might try to create a custom field bridge provider, which could get hold of the Spring application context through some static method. When provideFieldBridge() is called you may return a Spring-ified instance of that from the application context, assuming the timing is better and the DAO bean is available by then.
Not sure whether it'd fly, but it may be worth trying.
Hibernate Search 5.8.0 includes support for bean injection. You can see the issue https://hibernate.atlassian.net/browse/HSEARCH-1316.
However I couldn't make it work in my application and I had implemented a workaround.
I have created an application context provider to obtain the Spring application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
ApplicationContextProvider.context = context;
}
}
I have added it to the configuration class.
#Configuration
public class RootConfig {
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
}
Finally I have used it in a bridge to retrieve the spring beans.
public class AttachmentTikaBridge extends TikaBridge {
#Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
// get service bean from the application context provider (to be replaced when HS bridges support beans injection)
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ExampleService exampleService = applicationContext.getBean(ExampleService .class);
// use exampleService ...
super.set(name, content, document, luceneOptions);
}
}
I think this workaround it's quite simple in comparision with other solutions and it doesn't have any big side effect except the bean injection happens in runtime.

Resources