Tuesday, February 15, 2011
spring+wicket + quartz continues 2...
adding job execution triggers
//job listener implementation
public class Epb5JobExecutionListener extends org.quartz.listeners.JobListenerSupport {
public String getName() {
return "Epb5JobExecutionListener";
}
public void jobWasExecuted(
JobExecutionContext context,
JobExecutionException jobException
) {
//real implementation comes here
}
}
for example, if the job was successfully executed - jobException is null
and context.getJobDetail().getName() and context.getJobDetail().getJobClass() gives info which job was actually executed.
//in spring applicationContext.xml
<!-- scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="export2StatisticsTriggerBean" />
<ref bean="ldapUsersUpdateTriggerBean" />
</list>
</property>
<property name="globalJobListeners">
<list>
<bean class="at.kds.epb5.bl.Epb5JobExecutionListener"/>
</list>
</property>
</bean>
to sum up, the overall porting of exports implementation took me 3-5 more time than the initial implementation mostly because of the luck of detailed docs
//job listener implementation
public class Epb5JobExecutionListener extends org.quartz.listeners.JobListenerSupport {
public String getName() {
return "Epb5JobExecutionListener";
}
public void jobWasExecuted(
JobExecutionContext context,
JobExecutionException jobException
) {
//real implementation comes here
}
}
for example, if the job was successfully executed - jobException is null
and context.getJobDetail().getName() and context.getJobDetail().getJobClass() gives info which job was actually executed.
//in spring applicationContext.xml
<!-- scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="export2StatisticsTriggerBean" />
<ref bean="ldapUsersUpdateTriggerBean" />
</list>
</property>
<property name="globalJobListeners">
<list>
<bean class="at.kds.epb5.bl.Epb5JobExecutionListener"/>
</list>
</property>
</bean>
to sum up, the overall porting of exports implementation took me 3-5 more time than the initial implementation mostly because of the luck of detailed docs
Friday, February 11, 2011
spring+wicket + quartz continues...
the other scheduled job I need should update users from LDAP to the database
here are all bean definitions in applicationContext.xml
<!-- quartz scheduler related -->
<!-- jobs definitions -->
<!-- export to Austrian statistics -->
<bean id="export2StatisticsJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="scheduledexportservice"/></property>
<property name="targetMethod"><value>executeScheduledExportsIfAny</value></property>
<property name="concurrent" value="false"/>
</bean>
<bean id="ldapProperties" class="at.kds.epb5.common.LdapProperties" >
<property name="providerUrl"><value>ldap://here comes ip address/</value></property>
<property name="securityAuthentication"><value>simple</value></property>
<property name="securityPrincipal"><value>here comes user</value></property>
<property name="securityCredentials"><value>here comes pwd</value></property>
<property name="root"><value>dc=oeamtc,dc=at</value></property>
<property name="filter"><value>(&(objectclass=person) (| (sAMAccountName=a*) (sAMAccountName=t*)))</value></property>
<property name="userId"><value>sAMAccountName</value></property>
<property name="userFirstName"><value>givenName</value></property>
<property name="userLastName"><value>sn</value></property>
<property name="userValidTo"><value>accountExpires</value></property>
<property name="userPrefix"><value>a</value></property>
<property name="userClubCardNumber"><value>extensionAttribute13</value></property>
</bean>
<bean name="ldapUsersUpdateJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="at.kds.epb5.bl.EpbUsersUpdateJob" />
<property name="jobDataAsMap">
<map>
<entry key="ldapProperties" value-ref="ldapProperties"/>
<entry key="userservice" value-ref="userservice"/>
</map>
</property>
</bean>
<!-- cron trigger definitions -->
<bean id="export2StatisticsTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="export2StatisticsJob" />
<!-- run at 01 AM every day -->
<property name="cronExpression" value="0 0 01 * * ?" />
</bean>
<bean id="ldapUsersUpdateTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="ldapUsersUpdateJob" />
<!-- run at 02 AM every day -->
<property name="cronExpression" value="0 0 02 * * ?" />
</bean>
<!-- scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="export2StatisticsTriggerBean" />
<ref bean="ldapUsersUpdateTriggerBean" />
</list>
</property>
</bean>
where
public class EpbUsersUpdateJob extends QuartzJobBean {
@SpringBean
private UserService userservice;
LdapProperties ldapProperties;
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
//implementation not shown
}
//
}
here are all bean definitions in applicationContext.xml
<!-- quartz scheduler related -->
<!-- jobs definitions -->
<!-- export to Austrian statistics -->
<bean id="export2StatisticsJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="scheduledexportservice"/></property>
<property name="targetMethod"><value>executeScheduledExportsIfAny</value></property>
<property name="concurrent" value="false"/>
</bean>
<bean id="ldapProperties" class="at.kds.epb5.common.LdapProperties" >
<property name="providerUrl"><value>ldap://here comes ip address/</value></property>
<property name="securityAuthentication"><value>simple</value></property>
<property name="securityPrincipal"><value>here comes user</value></property>
<property name="securityCredentials"><value>here comes pwd</value></property>
<property name="root"><value>dc=oeamtc,dc=at</value></property>
<property name="filter"><value>(&(objectclass=person) (| (sAMAccountName=a*) (sAMAccountName=t*)))</value></property>
<property name="userId"><value>sAMAccountName</value></property>
<property name="userFirstName"><value>givenName</value></property>
<property name="userLastName"><value>sn</value></property>
<property name="userValidTo"><value>accountExpires</value></property>
<property name="userPrefix"><value>a</value></property>
<property name="userClubCardNumber"><value>extensionAttribute13</value></property>
</bean>
<bean name="ldapUsersUpdateJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="at.kds.epb5.bl.EpbUsersUpdateJob" />
<property name="jobDataAsMap">
<map>
<entry key="ldapProperties" value-ref="ldapProperties"/>
<entry key="userservice" value-ref="userservice"/>
</map>
</property>
</bean>
<!-- cron trigger definitions -->
<bean id="export2StatisticsTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="export2StatisticsJob" />
<!-- run at 01 AM every day -->
<property name="cronExpression" value="0 0 01 * * ?" />
</bean>
<bean id="ldapUsersUpdateTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="ldapUsersUpdateJob" />
<!-- run at 02 AM every day -->
<property name="cronExpression" value="0 0 02 * * ?" />
</bean>
<!-- scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="export2StatisticsTriggerBean" />
<ref bean="ldapUsersUpdateTriggerBean" />
</list>
</property>
</bean>
where
public class EpbUsersUpdateJob extends QuartzJobBean {
@SpringBean
private UserService userservice;
LdapProperties ldapProperties;
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
//implementation not shown
}
//
}
Thursday, February 10, 2011
spring+wicket + quartz
continuing with the porting of an old web app (written with struts1) to wicket+spring
where quartz was used for scheduling of exports & users update from LDAP to the database
my initial idea was to implement org.quartz.Job interface using a 'service' that does the actual export; these all ended to the service reference remain not initialized; all attempts to 'inject the dependency' failed.
final solution - using spring-context-support
(maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
)
then in applicationContext.xml:
<!-- quartz scheduler related -->
<!-- jobs definitions -->
<bean id="export2StatisticsJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="scheduledexportservice"/></property>
<property name="targetMethod"><value>executeScheduledExportsIfAny</value></property>
</bean>
<!-- cron trigger definitions -->
<bean id="export2StatisticsTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="export2StatisticsJob" />
<!-- run every day 5 minutes -->
<property name="cronExpression" value="0 0/5 * * * ?" />
</bean>
<!-- scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="export2StatisticsTriggerBean" />
</list>
</property>
</bean>
the key here is passing service bean scheduledexportservice as a value of targetObject property in export2StatisticsJob bean definition
where quartz was used for scheduling of exports & users update from LDAP to the database
my initial idea was to implement org.quartz.Job interface using a 'service' that does the actual export; these all ended to the service reference remain not initialized; all attempts to 'inject the dependency' failed.
final solution - using spring-context-support
(maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
)
then in applicationContext.xml:
<!-- quartz scheduler related -->
<!-- jobs definitions -->
<bean id="export2StatisticsJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="scheduledexportservice"/></property>
<property name="targetMethod"><value>executeScheduledExportsIfAny</value></property>
</bean>
<!-- cron trigger definitions -->
<bean id="export2StatisticsTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="export2StatisticsJob" />
<!-- run every day 5 minutes -->
<property name="cronExpression" value="0 0/5 * * * ?" />
</bean>
<!-- scheduler -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="export2StatisticsTriggerBean" />
</list>
</property>
</bean>
the key here is passing service bean scheduledexportservice as a value of targetObject property in export2StatisticsJob bean definition
Monday, February 7, 2011
wicket + form validation
when extending AbstractFormValidator
use FormComponent.getInput() / FormComponent.getConvertedInput() to validate the entered value - it is not yet saved to the component data mode, that's why validation of data model is not working
use FormComponent.getInput() / FormComponent.getConvertedInput() to validate the entered value - it is not yet saved to the component data mode, that's why validation of data model is not working
notes on Spring+JPA+Hibernate
having a mapping entity class & using a shared EntityManager
(
in "service" implementation
@PersistenceContext
private EntityManager entityManager;
)
1) "insert" query
@Transactional
public void scheduleExport(ScheduledExport export) {
if ( export == null ) return;
entityManager.persist(export);
}
2) annotations for ID generated with a sequence:
mapping entity class annotation
@Entity
@Table(name = "SCHEDULED_EXPORTS")
@SequenceGenerator(sequenceName="SEQ_SCHEDULED_EXPORTS",name="SEQ_SCHEDULED_EXPORTS")
public class ScheduledExport implements Serializable {
...
@Id
@Column(name="ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_SCHEDULED_EXPORTS")
private Integer id;
3) "delete" query
@Transactional
public void deleteExport(ScheduledExport export) {
if ( export == null ) return;
export = entityManager.merge(export);
entityManager.remove(export);
}
first call merge() and then remove() - otherwise getting java.lang.IllegalArgumentException: Removing a detached instance
4) when access to the data source is needed:
(again in service implementation)
@Autowired
DataSource dataSource;
(
in "service" implementation
@PersistenceContext
private EntityManager entityManager;
)
1) "insert" query
@Transactional
public void scheduleExport(ScheduledExport export) {
if ( export == null ) return;
entityManager.persist(export);
}
2) annotations for ID generated with a sequence:
mapping entity class annotation
@Entity
@Table(name = "SCHEDULED_EXPORTS")
@SequenceGenerator(sequenceName="SEQ_SCHEDULED_EXPORTS",name="SEQ_SCHEDULED_EXPORTS")
public class ScheduledExport implements Serializable {
...
@Id
@Column(name="ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_SCHEDULED_EXPORTS")
private Integer id;
3) "delete" query
@Transactional
public void deleteExport(ScheduledExport export) {
if ( export == null ) return;
export = entityManager.merge(export);
entityManager.remove(export);
}
first call merge() and then remove() - otherwise getting java.lang.IllegalArgumentException: Removing a detached instance
4) when access to the data source is needed:
(again in service implementation)
@Autowired
DataSource dataSource;
Subscribe to:
Posts (Atom)