How to configure JBoss/Quartz to run Spring job? - spring

I'm new to JBoss, having been using tomcat for years. I have a Spring 3.0.x application in which I need to run a job on a regular basis. In the past, I would simply create my job class as a regular POJO, and then create my job/trigger as Spring's CronTriggerBean passing a MethodInvokingJobDetailFactoryBean as my jobDetail.
Ex:
<bean id="session.manage.UserSessionPurgeAction.trigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="cronExpression" value="0 */5 * * * ? *" />
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="name"><idref bean="session.manage.UserSessionPurgeAction" /></property>
<property name="group" value="cleanup" />
<property name="targetObject" ref="session.manage.UserSessionPurgeAction" />
<property name="targetMethod" value="execute" />
<property name="concurrent" value="false" />
</bean>
</property>
</bean>
On this new project, the system architect has called for running the Spring application under JBoss 6. I know that JBoss has a quartz scheduler built in, so I am not sure how to package/declare my job such that it is using JBoss' scheduler as opposed to building it into the app as I have done in the past.
I've searched online, but cannot seem to find the necessary glue information that I need. I know that there is a #Schedule annotation in javax.ejb but is that all I need to add to my method? I would think/expect that I need additional configuration somewhere, but not sure where.
Can anyone point me in the right direction please?
Thanks,
Eric

If you really want to use the jboss one, I would try matching the schedulerName property passed to SchedulerFactoryBean with one of the bundled scheduler. The bundled scheduler can be retrieved via JNDI, it's under jndi name "Quartz" I think.
Have a look at org.springframework.scheduling.quartz.SchedulerFactoryBean#createScheduler, it tries to look up the scheduler in static SchedulerRepository first.

Related

Spring boot unable to create multiple rabbit connection factories

I am trying to connect to and consume from two different clusters of rabbitmq using a spring boot app via xml. It works well when a single rabbit:connection-factory bean is created in the application context. However, when the second one is added, it fails to start the application with the error "Parameter 1 of method rabbitListenerContainerFactory in org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration required a single bean, but 2 were found:". How do I go about creating different factories per cluster? Please suggest an alternative way of doing this, if it's not the right approach?
Here is the xml snippet:
<rabbit:connection-factory id="firstConnectionFactory" connection-factory="firstSpringConnectionFactory" />
<rabbit:connection-factory id="secondConnectionFactory" connection-factory="secondSpringConnectionFactory"/>
<bean id="firstSpringConnectionFactory"
class="org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean">
<property name="useSSL" value="${rabbitmq.ssl.enabled}" />
<property name="host" value="${rabbitmq.first.host}"/>
<property name="virtualHost" value="${rabbitmq.vhost}"/>
<property name="port" value="${rabbitmq.cluster.port}"/>
<property name="username" value="${rabbitmq.user}"/>
<property name="password" value="${rabbitmq.first.password}"/>
</bean>
<bean id="secondSpringConnectionFactory"
class="org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean">
<property name="useSSL" value="${rabbitmq.ssl.enabled}" />
<property name="host" value="${rabbitmq.second.host}"/>
<property name="virtualHost" value="${rabbitmq.vhost}"/>
<property name="port" value="${rabbitmq.cluster.port}"/>
<property name="username" value="${rabbitmq.user}"/>
<property name="password" value="${rabbitmq.second.password}"/>
</bean>
And the listener container code:
ConnectionFactory cf = rabbitConnectionFactory;//One of the connnection factories will be injected here from app context
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(cf);
container.setConcurrentConsumers(count);
container.addQueueNames(queueName);
container.setMessageListener(listener);
container.start();
Since you don't rely on the Spring Boot here and don't use Spring AMQP annotation support I suggest you to exclude RabbitAnnotationDrivenConfiguration from auto-configuration:
#EnableAutoConfiguration(exclude={RabbitAnnotationDrivenConfiguration.class})
spring.autoconfigure.exclude = org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration
If you still need #RabbitListener somewhere in other place of your project, you only have a choice to build all the #EnableRabbit infrastructure manually.

Flyway Spring JPA2 integration - possible to keep schema validation?

Hy, i have a webapplication where i am trying to integrate JPA2(Hibernate)+Spring+Flyway
I added flyway to my ApplicationContext like this:
<bean id="flyway" class="org.flywaydb.core.Flyway" init-method="migrate">
<property name="baselineOnMigrate" value="true" />
<property name="dataSource" ref="dataSource" />
</bean>
Theoretically this works fine and updates the schema with scripts that i save under db/migration. So far so good.
The one problem that is left for me is that if i change something (e.g. adding a String field to an Entity) the application won't even get this far because Hibernates Schema-Validator will throw something like this: Caused by: org.hibernate.HibernateException: Missing column: showCaseField in demo.testEntity. This happens because i have set "hibernate.hbm2ddl.auto" to "validate"
Now i have read about Hibernate failing to recognize perfeclty valid schemas in some (rare?) cases and i MAY (or not) reach a point someday where i disable this feature altogether. But as of now i actually like the extra-validation and don't want to turn it off.
Is it possible to integrate Spring and Flyway while still keeping Hibernates-Schema-Validation? I guess this could be a problem, because Flyway probably depends on a DataSource-bean or something and in conclusion requires the applicationContext to be completely initialized, which in turn Hibernate prevents because of the schema mismatch..
Any ideas?
Found the answer now. Basically all you have to do is letting your entityManagerFactory-bean depend on your Flyway bean (there's an attribute for that). Now Flyway (and in turn your dataSource) is initialized first and the Flyway-Scripts are executed before Hibernates schema-validation
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="flyway"> ....
</bean>
<bean id="flyway" class="org.flywaydb.core.Flyway" init-method="migrate">
<property name="baselineOnMigrate" value="true"/>
<property name="dataSource" ref="dataSource"/>
</bean>

How to use poller trigger in spring integration int-jpa:inbound-channel-adapter such that trigger persist in DB

I have spring integration inbound adapter which works just fine, below. And I also have setup Quartz in cluster mode (hence persist the trigger/scheduler) in DB. It works fine as well, for Job that extends org.quartz.Job class. I am trying to make the the poller in int-jpa:inbound-channel-adapter to be in cluster mode, so that even when it is deployed in multiple nodes only one of it is running. I got the idea of doing to so for serviceactivator but I am not sure how to do this for scenario like mine where I am using int-jpa:inbound-channel-adapter. I am using spring 4 and Quartz 2.
<int-jpa:inbound-channel-adapter
id="inboundChannelAdapterIIDDataJpa"
channel="inboundChannelAdapterOne"
entity-manager="entityManager"
jpa-query="select g from House g"
expect-single-result="false"
delete-after-poll="false">
<int:poller fixed-rate="50000">
<int:transactional propagation="REQUIRED"
transaction-manager="transactionManager" />
</int:poller>
</int-jpa:inbound-channel-adapter>
I tried to replace poller ( above ) with
and
then define cron like this;
<bean id="mytrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="cronExpression" value="0 0/5 * * * ?" />
<property name="jobDetail" ref="inboundChannelAdapterIIDDataJpa" />
</bean>
Here jobDetail ref to the adaptor id. And then have "mytrigger" within scheduler
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="mytrigger" />
</list>
</property>
</bean>
But it does not work. I am looking for the solution such that the trigger could be in cluster mode keeping trigger info in quartz table.

Nested Spring TxProxyTemplate issue

I have the following config.
<bean id="abcManager" parent="TxProxyTemplate">
<property name="target">
<bean class="com.x.y.AbcManagerImpl">
<property name="abcDAO" ref="abcDAO"/>
<property name="xyzManager" ref="xyzManager"/>
</bean>
</property>
</bean>
<bean id="xyzManager" parent="TxProxyTemplate">
<property name="target">
<bean class="com.x.y.XyzManagerImpl">
<property name="abcDAO" ref="abcDAO"/>
<property name="anotherManager" ref="anotherManager"/>
</bean>
</property>
</bean>
<bean id="anotherManager" parent="TxProxyTemplate">
<property name="target">
<bean class="com.x.y.AnotherManagerImpl">
<property name="abcDAO" ref="abcDAO"/>
<property name="oneMoreManager" ref="oneMoreManager"/>
</bean>
</property>
</bean>
What is the issue with the following configuration? will having the same DAO at the different levels cause concurency issues?
We found that we get lots of weblogic connection releases when we have high load.
How is this related to the connection release issue?
We use Hibernate for DAO operations.
First, analyse the logs to see when spring creates and closes transactions.
Set the logger for org.springframework.transaction to DEBUG for this.
Next my guess is you need to examine your #Transactional annotations (which I assume you use on your managers (=services?). Make sure the propagation is set correctly because this might be related to your issue (hard to say without seeing your manager's code of course).
To answer your question directly:
What is the issue with the following configuration? will having the same DAO at the different levels cause concurency issues?
Nothing, and no. I don't see anything wrong with this. Not sure what you mean about 'same DAO' - you don't have the same DAO. You have the same parent, but 3 distinct DAOs.
If you're asking, then, why is weblogic closing your DB connections before your transaction completes, we wouldn't be able to answer that with the information above.

host/role dependent spring configuration

I have a cluster of servers running a spring application. Some of the spring components need to be configured differently depending on the role their server is playing (primary, secondary, etc). I don't want to maintain separate spring config files for each role, rather I want to dynamically detect this when the application is started. Its almost like I want conditional bean instantiation (which doesn't exist in spring).
Q: What is the best way to achieve this type of configuration?
Example: Only the primary node in a cluster should create durable subscription to a JMS broker (which requires a globally unique JMS clientID). I can detect if the current host has this role by looking up the running server's hostname in a database and start this container manually (if my node happens to be primary); however, I don't want every node in the cluster to create a durable subscription (by instantiating this bean).
<bean id="auditrecordListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1" />
<property name="clientID" value="${server-hostname}" />
<property name="durable" value="true" />
<!-- only started on the primary node: via application listener -->
<property name="autoStartup" value="false" />
</bean>
Note, however there is no ${server-hostname} property in the spring container (at least that I know of)
If your code already conditionally starts the appropriate services based on object properties, you can use utility methods in the following manner:
<!-- Factory methods to determine properties -->
<bean id="hostname" class="MyUtil" factory-method="determineHostName"/>
<bean id="isHost" class="MyUtil" factory-method="isHost"/>
<bean id="auditrecordListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1" />
<property name="durable" value="true" />
<!-- Reference properties here -->
<property name="hostname" ref="hostname" />
<property name="autoStartup" ref="isHost" />
</bean>
To use a property of a singleton bean instead, use a PropertyPathFactoryBean:
<bean id="config" class="MyConfig"/>
<util:property-path id="hostname" path="config.hostname"/>
<util:property-path id="isHost" path="config.host"/>
You can implement a conditional instantiation logic
as a FactoryBean

Resources