How to get the Job Instance of Long Running Jobs in Quartz? - quartz-scheduler

I have created my own job class by extending the default class added couple of member variables and member methods. I saw the job gets triggered and is running for a very long time.
I just wanted to get the Job Instance not the JobDetail and wanted to invoke any member methods which has been defined by me or wanted to access the member variables.
Could you please let me know how we can achieve this?
Thanks,
Kathir

There is not such way, probably because quartz is meant to be compatible with a remote scheduling mode (i.e. cluster).
But if you are using it in a single server / application context, you could probably implement your own JobFactory (http://quartz-scheduler.org/api/2.1.5/org/quartz/simpl/SimpleJobFactory.html) that will just delegate to the super class the creation of the instance, and then register the instance somehow in a map or something else. Then you'll have to loop over the map keys to find the instance you are looking at.
Be careful of memory leaks with such a solution
Quick example:
In your spring configuration file:
<!-- quartz scheduler -->
<bean id="orchestration-api-quartz-factory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:spring/quartz.properties"/>
<property name="jobFactory">
<bean class="service.scheduler.SpringServiceJobFactory"/>
</property>
</bean>
And the basic implementation of your Factory:
/**
* This job factory tries to locate the spring bean corresponding to the JobClass.
*
* #author Mathieu POUSSE
*/
public class SpringServiceJobFactory extends SpringBeanJobFactory implements JobFactory {
#Autowired
private ApplicationContext context;
/**
* {#inheritDoc}
*/
#Override
protected Object createJobInstance(final TriggerFiredBundle bundle)
throws Exception {
// create or get the bean instance
Object bean = this.context.getBean(bundle.getJobDetail().getJobClass());
// do what you want with the bean
// but remeber what you did, otherwise if you forget to forget
// you will have memory leaks !!!
// myConcurrentMap.put("job.key", bean);
return bean ;
}
}
HIH

Related

Spring Data MongoDB #Transactional isn't working?

I have below maven dependency & configuration set up
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
#Configuration
#EnableMongoAuditing
public class MongoConfig {
#Bean
MongoTransactionManager transactionManager(MongoDbFactory mongoDbFactory) {
return new MongoTransactionManager(mongoDbFactory);
}
}
Updated: I've taken the suggested solution to create a bean with #Transactional, and have it injected into my test class. Below is the service bean I created:
#Service
#Transactional
#RequiredArgsConstructor
public class MongoTransactionService {
private final UserRepo userRepo;
public void boundToFail() throws RuntimeException {
userRepo.save(User.builder().id("1").build());
throw new RuntimeException();
}
}
and test class where I inject a bean of MongoTransactionService:
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class,
includeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MongoTransactionService.class))
#ExtendWith(SpringExtension.class)
class MongoTransactionServiceTest {
#Autowired
UserRepo userRepo;
#Autowired
MongoTransactionService mongoTransactionService;
#Test
void testTransactional() {
try {
mongoTransactionService.boundToFail();
} catch (Exception e) {
// do something
}
val user = userRepo.findById("1").orElse(null);
assertThat(user).isNull();
}
}
I am expecting a call to boundToFail(), which throws a RuntimeException, would roll back the saved user, but the user still gets persisted in the database after the call.
It turns out that #DataMongoTest doesn't activate the auto-configuration for MongoDB transactions. I've filed a ticket with Spring Boot to fix that. In the mean time, you can get this to work by adding
#ImportAutoConfiguration(TransactionAutoConfiguration.class)
to your test class.
Note that using MongoDB transactions requires a replica set database setup. If that's not given the creation of a transaction will fail and your test case will capture that exception and the test will still succeed. The data will not be inserted but that's not due to the RuntimeException being thrown but the transaction not being started in the first place.
The question previously presented a slightly different code arrangement that suffered from other problems. For reference, here's the previous answer:
#Transactional needs to live on public methods of a separate Spring bean as the transactional logic is implemented by wrapping the target object with a proxy that contains an interceptor interacting with the transaction infrastructure.
You example suffers from two problems:
The test itself is not a Spring bean. I.e. there's no transactional behavior added to boundToFail(…). #Transactional can be used on JUnit test methods but that's controlling the transactional behavior of the test. Most prominently, to roll back the transaction to make sure changes to the data store made in the test do not affect other tests. See this section of the reference documentation.
Even if there was transactional logic applied to boundToFail(…), a local method call to the method would never trigger it as it doesn't pass the proxy that's applying it. See more on that in the reference documentation.
The solution to your problem is to create a separate Spring bean that carries the #Transactional annotation, get that injected into your test case and call the method from the test.

Spring Data JPA: Repositories for multiple database / Entitymanger configurations

I have two Entitymanager bean configurations. Each pointing to a separate database with a different schema (one is Oracle, the other one is an in-memory H2)
What could I do to solve the ambiguity of what Entitymanager should be used for each Repository? Right now I'm getting this error:
No unique bean of type [javax.persistence.EntityManagerFactory] is defined:
expected single bean but found 2
I guess I could provide a quick-fix simply by using something like
<jpa:repositories base-package="com.foo.repos.ora"
entity-manager-factory-ref="entityManagerFactoryA">
<jpa:repositories base-package="com.foo.repos.m2"
entity-manager-factory-ref="entityManagerFactoryB">
But hopefully there is a better solution.
EDIT:
I give you an idea of the current scenario:
Spring-Config: there're two EM
<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/>
<jpa:repositories base-package="com.foo.repos.m2" entity-manager-factory-ref="entityManagerFactory2"/>
<context:component-scan base-package="com.foo" /> ....
Everything from here on is in "package com.foo.repos.ora"
Following the pattern of how to make a custom repository I get two interfaces 'ARepository', 'ARepositoryCustom' and its implementation 'ARepositoryImpl' like so
#Repository
public interface ARepository extends ARepositoryCustom, JpaRepository<myEntity, BigDecimal>, QueryDslPredicateExecutor {
}
public interface ARepositoryCustom {
FooBar lookupFooBar()
}
public class ARepositoryImpl extends QueryDslRepositorySupport implements ARepositoryCustom {
ARepositoryImpl(Class<?> domainClass) {
super(domainClass.class)
}
ARepositoryImpl() {
this(myEntity.class)
}
#Override
FooBar lookupFooBar() {
JPQLQuery query = ....
....
return found
}
}
resulting in the following error message:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'aRepositoryImpl': Injection of
persistence dependencies failed; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [javax.persistence.EntityManagerFactory] is
defined: expected single bean but found 2
Which is of course correct, there are 2 EM beans, but since I restricted EM #1 aka 'entityManagerFactory' to package 'com.foo.repos.ora' only, I'm still not sure how to reference the exact EM bean.
There is no magic under the hood.
<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/>
doesn't help you at all with your custom interface implementations. Best way I found is to treat your custom implementations as regular beans. So I defined a 'sharedEntitManager' bean in my spring configuration like so
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>
<bean id="sharedEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name = "entityManagerFactory" ref="entityManagerFactory"/>
</bean>
After that, I simply injected the EntityManager into my implementation beans
<bean id="aRepositoryImpl" class="comm.foo.repos.ora.ARepositoryImpl">
<property name="entityManager" ref="sharedEntityManager"/>
</bean>
The 'entity-manager-factory-ref' attribute discriminates between different entitymanager factories but only for straight Spring Data Repositories (i.e. only for interfaces). It doesn't however concern itself with any of your implementations.
To sum it up
1) if you simply rely on standard Spring Data repositories with no custom implementation, use the "entity-manager-factory-ref" attribute to differentiate databases.
2a) Additionally, if you use any custom implementation, inject the appropriate EntityManager directly into the implementing class. Wirering is done under control of your spring xml configuration. For some reason I wasn't able to use the #Autowire annotation with a #Qualifier to reference the correct EntityManager. EDIT I just learned about the #Resource annotation
#Resource(name = "sharedEntityManagerA")
EntityManager entityManager
<bean id="sharedEntityManagerA" name="sharedEntityManagerA" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name = "entityManagerFactory" ref="entityManagerFactory"/>
</bean>
With this at hand selecting what EntityMAnger should be used becomes straightforward. No need of plumbing everything togehther in your context xml.
2b) As an alternative to Spring's xml configuration for hooking up your stuff you may also go with
#PersistenceContext( unitName = "nameOfPersistenceUnit" )
to inject the correct EntitymanagerFactory
While 'nameOfPersistenceUnit' referes to your persistence sitting in your standard JPA persistence.xml
However 2b) doesn't go well with 'QueryDslRepositorySupport', since it expects an EntityManager instance. But I found that 'QueryDslRepositorySupport' doesn't offer much support anyway, so I removed it.

Explain RestEasy providers, resources and singletons in relation to classes vs instances?

I'm building a JAX-RS app that consists of a stockroom and a workplace. The stockroom holds a set of Java classes that can be instantiated (via AJAX) to create named instances of those classes in the workplace.
So far I'm able to reference the stockroom and workplace fine by declaring them as "singletons" in the RestEasy application
singletons.add(StockPlace.getInstance());
singletons.add(WorkPlace.getInstance());
I'm unable to understand how to understand how the stockroom content classes should be handled. The effect I'm trying to achieve is that when I dynamically create an instance of one of the stockroom classes, that instance can be dynamically accessed via REST commands. I've tried various permutations of:
classes.add(SomeComponent.class);
I think I'm missing knowledge of how the Java notion of how classes work as factories for making instances, and how both of these relate to what RestEasy calls classes, singletons (singletons ARE classes, yet RestEasy registers them as instances) and resources (instances?).
I suspect I'll wind up needing to dynamically register new instances but can't find a way to do that either. I did find a way to do it given the ServletContext, but am not able to get access to that either. Can someone get me on the right track?
Our eventual answer to this question was to bail out of RestEasy and convert to DropWizard. That problem and many others vanished and everything became easy again.
I believe I know what you are after, but I should at least give you a push in the right direction.
You will need to add the annotated RESTEasy class(es) to the registry. Below is the class I used for a recent project. It adds to the singletons (per what you did) but it also adds to the registry.
public class RESTEasyServerApplication extends javax.ws.rs.core.Application
{
// The RESTEasy registry
#Autowired
protected org.jboss.resteasy.spi.Registry registry;
// The annotated RESTEasy handler classes
private Set<Object> singletons = new HashSet<Object>();
private List<Object> handlers = new ArrayList<Object>();
public RESTEasyServerApplication()
{}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
// Spring injection support
public void setHandlers( List<Object> handlers )
{
for( Object handler : handlers )
{
if( registry != null )
{
// Save a reference to the handler
this.handlers.add( handler );
// Register the handler with RESTEasy
registry.addSingletonResource( handler );
}
singletons.add( handler );
}
}
// Spring injection support
public List<Object> getHandlers()
{
return handlers;
}
}
I used Spring, and here is the relevant configuration:
<!-- RESTeasy/Spring integration -->
<import resource="classpath:springmvc-resteasy.xml" />
<!-- RESTeasy server application -->
<bean id="application" class="blah.blah.resteasy.RESTEasyServerApplication">
<property name="handlers">
<list>
<!-- Application specific handler classes -->
<ref bean="sample"/>
</list>
</property>
</bean>
Should be easy to modify/add a method to accept a single annotated RESTEasy class and make it work dynamically as required. The registry is defined in the springmvc-resteasy.xml file.
Since I've found no answers that don't involve strapping another whole layer of complexity (Spring) onto RestEasy, the solution I found livable is outlined in the final comment above. That is, don't rely on sending remote messages to instances unless the app is truly stateless (e.g. instances don't persist across messages). Only send remote messages to singletons which do persist across requests. Each such message can identify the desired instance (by String id in my case), and the singleton can forward to the identified instance as an ordinary POJO.
I still don't see why RestEasy unconditionally treats non-Singletons (instances) as ephemeral. Statelessness is not a restriction on REST, only a restriction on when GET methods can be used (idempotent calls). PUT and POST calls are neither stateless nor idempotent.
As I understand this, of course, and feel free to correct me. My focus is getting this app on the air, not exploring every corner of RestEasy, REST, and certainly not Spring.

Notify parent context object about child context object creation

this is a situation I would like to implement.
public class ComponentRepository
{
public void Register(IComponent component)
{
// store component in collection
}
}
<!-- root context -->
<object id="Repository" type="NameSpace.ComponentRepository" />
<!-- child context (0 - n contexts) -->
<object id="Component" type="NameSpace.Component"/>
I would like to register all IComponent objects with ComponentRepository. I suppose it can be done with some kind of publish/subscribe mechanism, but I would like to keep my classes clean (without implementing any of spring.net interfaces).
What is the best way to achieve this?
I understood your question as this:
After the instantiation of the child-context's Component, the Register-method of a ComponentRepository defined in another context should be called.
As far as I know, there is no xml-declarative way to achieve what you want.
I would suggest to either make your ComponentRepository IApplicationContextAware (which is what you explicitly don't want) or to create a new IApplicationContextAware Class which takes a dependency of ComponentRepository.
That way you can call the ApplicationContext's GetObjectsOfType Method and retrieve all IComponent objects to pass to the ComponentRepository.

Jersey / ServletContext and resource loading on startup

I'm kind of new in web development with Java.
I am developing a web service and I've chosen REST / Jersey for it.
I want to init some stuff on startup of the service and to keep them
all along the life of the service.
First question : Is the constructor of the Jersey Servlet a good place to do that ?
Basically, what I want to do is to load a config.ini file located in my WEB-INF directory.
Following this help, I understand I need a ServletContext to load my file as a resource.
However, it is not clear to me how to get this ServletContext in a Jersey Servlet, as it is not really an instance of a servlet, but rather a POJO with some annotations.
I wanted to try this tip, but the attribute "context" is null in the constructor. I think that Jersey might populate it after the constructor. Right ?
So how is the right way to do this ?
Here is my code so far :
/** Main REST servlet */
#Path("/")
public class Servlet {
// ----------------------------------------------------
// Constants
// ----------------------------------------------------
static private final String CONFIG_PATH = "/WEB-INF/config.ini";
// ----------------------------------------------------
// Attributes
// ----------------------------------------------------
/** Context */
#Context ServletContext context;
// ----------------------------------------------------
// Constructor
// ----------------------------------------------------
/** Init the servlet */
public Servlet() {
// Load config.ini from WEB-INF
Config.config = new Config(
this.context.getResourceAsStream(CONFIG_PATH));
// FAIL! this.context is null ...
}
// ----------------------------------------------------
// URI Handlers
// ----------------------------------------------------
/** Welcome page */
#GET
#Path("/")
#Produces(MediaType.TEXT_HTML)
public String welcome() {
return "<h1>Hi there.</h1>";
}
}
Any help would be much appreciated.
Thanks in advance,
Raphael
Using a ContextListener isn't the JAX-RS way to do this-- the ContextListener is the "next layer down," as it were, in the servlet API.
You can put the annotated declaration in the constructor parameters and it will be passed to the constructor:
public Servlet(#Context ServletContext context) {
Using the #Context annotation for a data member initializes that member after the object is constructed, as you discovered.
Another way to do this is to move the initialization of the Config object into some sort of init call, and only initialize it when it's needed, i.e. lazy initialization. Then the ServletContext data member will already have been set by the Jersey framework.
Good Luck!
Kirk
I am not familiar with Jersey, but generally in a Java web application, I think the right thing to do would be to create a ContextListener.
A context listener is a class that implements the interface javax.servlet.ServletContextListener and is configured in your web.xml. It has a method that is executed when the application is first loded into your container, and another one that is executed when the application is stopped, so it is the ideal place to put some one-time initialization stuff, and clean-up things before the application is stopped.
So the steps are :
create your Listener class, implement the contextInitialized(ServletContextEvent sce) method. In this method you receive a ServeltContextEvent that has getServletContext() method that gives you access to the ServletContext.
Configure your Listener in your web.xml
You'll find additional info here : tutorial
Or on Sun's, er, Oracle's site.
By the way, if your file will be in a JAR file I am not sure that the ServletContext method is the best way to load it. I think you're better off with somethinbg like :
this.getClass().getClassLoader().getResourceAsStream("com.company.my.file.properties");