Tuesday, February 15, 2011

spring related links that might be helpful

Spring – How to do dependency injection in your session listener

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

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>(&amp;(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

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

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;