Powered By Blogger
Showing posts with label spring. Show all posts
Showing posts with label spring. Show all posts

Sunday, June 24, 2012

Web application context (spring load)

Following is an example of how spring beans can be loaded from a servlet. 

The web.xml configuration required is as follows. The spring bean definition xml file path should be given as a context parameter. Spring's ContextLoaderListener has to be defined as a listener in the web.xml. The sub-element 'load-on-startup' should be present in the servlet definition for the servlet to load at the web application is deploy time (If not the servlet will be initialized upon the first request to it).

 ==================================================================
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-beans.xml</param-value>
    </context-param>
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/log4j.xml</param-value>
        <description>location of log4j configuration file, used by log4jconfiglistener</description>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>InitServlet</servlet-name>
        <servlet-class>com.shyarmal.servlet.InitServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
   
    <servlet-mapping>
        <servlet-name>InitServlet</servlet-name>
        <url-pattern>/init</url-pattern>
    </servlet-mapping>

</web-app>
 ==================================================================

The servlet code is below. The method, init(ServletConfig) [or init()] is overridden to load the web application context with, "WebApplicationContextUtils .getWebApplicationContext(config.getServletContext());". Servlet's init is called when the same is initialized.

 ==================================================================

package com.shyarmal.servlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;



public class InitServlet extends HttpServlet {

    private static final Logger LOGGER = LoggerFactory.getLogger(InitServlet.class);

    @Override
    public void init(ServletConfig config) throws ServletException {
        try {
            LOGGER.debug("initializing email service.");
            ApplicationContext ac = WebApplicationContextUtils              .getWebApplicationContext(config.getServletContext());
            LOGGER.info("Started email service.");
        } catch (Exception e) {
            LOGGER.error("Failed to load application context.", e);
        }
        super.init(config);
    }
}

 ==================================================================


thanks,
Shyarmal.


Wednesday, December 28, 2011

Open Session In View Filter Usage

Open Session In View Filter of Spring framework takes care of hibernate session management of a web application.  The integration of it is done at the web.xml.

Firstly, the spring beans ought to be loaded to the application context. This is done with a 'context-param' element. Secondly, define a filter with a 'filter' element (here my filter class is com.shyarmal.filter.MyOpenSessionInViewFilter which extends org.springframework.orm.hibernate3.support.OpenSessionInViewFilter).  Thirdly, define a filter mapping to the filter appropriately using 'filter-mapping' element. Notice the init parameter (sessionFactoryBeanName) passed to the filter. It is the id of the session factory defined in spring beans xml configurations.

web.xml elements of interest are as follows.
===================================================================
<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</context-param>

<filter>
   <filter-name>openSessionInViewFilter</filter-name>
   <filter-class>com.shyarmal.filter.MyOpenSessionInViewFilter</filter-class>
   <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
   </init-param>
</filter>

<filter-mapping>
        <filter-name>openSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>
===================================================================

Following are the spring bean definitions related to session factory used for the integration of open session in view filter.
===================================================================

<bean id="hibernateConfigProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
   <property name="location">
       <value>classpath:hibernate.properties</value>
   </property>
</bean>

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="${jdbc.driver.class.name}"/>
   <property name="url" value="${jdbc.url}"/>
   <property name="username" value="${jdbc.username}"/>
   <property name="password" value="${jdbc.password}"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
            <value>Accounts.hbm.xml</value>
             .....
            .....
            .....
        </list>
    </property>
    <property name="hibernateProperties" ref="hibernateConfigProperties"/>
</bean>

===================================================================

thanks,
Shyarmal.

Wednesday, July 27, 2011

Quartz 2.0 with Spring

I was entrusted with writing a scheduler, which is to run at a fixed time daily and it was decided to use quartz for this purpose. First the task was done using spring integration classes for quartz. But unfortunately, problems arose. Quartz 2.x versions have been refactored and no longer can be used with spring integration support. Some of the classes of older versions of quartz have been made interfaces in version 2.0.

Since I couldn't find a comprehensive example of how to schedule a task using quartz 2.0, I decided to post this example, hoping it would be useful to someone.Initialization of the scheduler is done in the init() method and the actual task need to be done is written in the inner class, AdminJob.

The following code schedules a task, which will be run daily at a fixed time.
=====================================================

package com.shyarmal.admin.jobs;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.List;

import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AdminTask {

    private static NotificationSender notificationSender;
    private static Client client;
    private String cronExpression;
    private static final String JOB_NAME = "admin-job";
    private StdSchedulerFactory stdSchedulerFactory;
    private Scheduler scheduler;
    private static final Logger LOGGER = LoggerFactory.getLogger(AdminTask.class);
  
    public void init() {
        try {
            LOGGER.info("initializing admin notify scheduler .... ");
            scheduler = stdSchedulerFactory.getScheduler();
            if(scheduler.checkExists(JobKey.jobKey(JOB_NAME))) {
                scheduler.deleteJob(JobKey.jobKey(JOB_NAME));
            }
            JobDetail job =  newJob(AdminJob.class).withIdentity(JOB_NAME).build();

            CronTrigger trigger = newTrigger()
                    .withIdentity("admin-notify", "priority")
                    .withSchedule(cronSchedule(cronExpression)).forJob(JOB_NAME)
                    .build();
          
            scheduler.scheduleJob(job, trigger);
            LOGGER.info("initialized admin notify scheduler .... ");
        } catch (Exception e) {
            LOGGER.warn("scheduler initialization failed .... ", e);
        }
    }
  
    public void destroy() {
        try {
            LOGGER.info("interrupting job ... ");
            scheduler.deleteJob(JobKey.jobKey(JOB_NAME));
        } catch (Exception e) {
            LOGGER.warn("couldn't interrupt job ... ", e);
        }
    }

  
    public static class AdminJob implements Job {

        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
          
             List<Notification> notifications = notificationSender.create();
             if (!notifications.isEmpty()) {
                 LOGGER.info("Sending notification .... ");
                 if(!client.send(notifications.get(0))){
                     LOGGER.error("failed to send notification ... ");
                 }
             }
        }

    }

    public void setNotificationSender(NotificationSender notificationSender) {
        AdminTask.notificationSender = notificationSender;
    }

    public void setClient(Client client) {
        AdminTask.client = client;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    public void setStdSchedulerFactory(StdSchedulerFactory stdSchedulerFactory) {
        this.stdSchedulerFactory = stdSchedulerFactory;
    }
  
}

=====================================================

What happens in init()

A scheduler is obtained from the standard sheduler factory (injected through spring) and if a job by the name, admin-job exists it will be removed. A new JobDetail is created with the job key, admin-job. Then a CronTrigger (with trigger key, admin-notify and group, priority) is created for the admin-job. The cron expression is configured. Then the job is scheduled.

What happens in destroy()

The job created is deleted here. This is not guaranteed to run since sometimes the system will not be shut down cleanly.

The inner class, AdminJob

 This is the job class used when creating the JobDetial instance. It should implement org.quartz.Job and override the method, execute(JobExecutionContext), which is called by the scheduler at the time scheduled. So the actual work to be carried out goes in here. An important thing to note is that this class has to be public and static (if not instantiation of it fails).

The reason for using an inner class rather than a separate class was to access the fields injected to the outer class (AdminTask) to be directly accessible. If not the corresponding fields will be needed to put in the JobDataMap of JobDetail and access via the JobExecutionContext instance passed to execute(JobExecutionContext). The major issue here is the contents of JobDataMap need to be serializable. 


The spring configuration of AdminTask and quartz standard scheduler factory are as follows. The cron expression can be configured through a properties file. When making the scheduler factory I have passed the property, org.quartz.jobStore.class to be org.quartz.simpl.RAMJobStore. This is to make my triggers run in the memory (RAM), so that they'll be destroyed when the system is turned off.
=====================================================

    <bean id="adminTask" class="com.shyarmal.admin.jobs.AdminTask"
        init-method="init"
        destroy-method="destroy"
        p:client-ref="client"
        p:notificationSender-ref="notificationSender"
        p:cronExpression="${prop.admin.task.cron.expr}"
        p:stdSchedulerFactory-ref="stdSchedulerFactory"/>

      
    <bean id="stdSchedulerFactory" class="org.quartz.impl.StdSchedulerFactory">
        <constructor-arg type="java.util.Properties" ref="quartzProperties"/>
    </bean>
  
    <util:properties id="quartzProperties">
        <prop key="org.quartz.jobStore.class">${prop.org.quartz.jobStore.class}</prop>
    </util:properties>

=====================================================
properties used in the properties file
=====================================================

prop.admin.task.cron.expr = 0 15 10 * * ? *
prop.org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

thanks,
Shyarmal.

Wednesday, July 20, 2011

Spring e-mail example

This is an illustration of how e-mails can be sent using spring framework.

Below is the class written to send e-mails. It's fields, mailSender and emailSubject are injected through spring (The spring configurations can be found at the end of the post). MailSender referred to here is an instance of org.springframework.mail.javamail.JavaMailSenderImpl, the class used to send e-mails in Spring.
In the method send of EmailClient an instance of SimpleMailMessage is created and required attributes such as recipient, sender, e-mail body content, subject and optional parameters like cc, bcc are set. MailSender class's 'send' method is used to send the email.

=========================================================
package com.shyarmal.messaging;

import com.shyarmal.messaging.domain.EmailMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;

public class EmailClient {

    private MailSender mailSender;
    private String emailSubject;
    private static final Logger LOGGER = LoggerFactory.getLogger(EmailClient.class);

    public void send(EmailMessage message) {
        try {
            if(LOGGER.isDebugEnabled()) {
                LOGGER.debug("email message [{}]", message);
            }
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            mailMessage.setSubject(emailSubject);
            mailMessage.setText(message.getText());
            mailMessage.setFrom(message.getFrom());
            mailMessage.setTo(message.getTo());
            if(message.getCc() != null && !message.getCc().isEmpty()) {
                mailMessage.setCc(message.getCc());
            }
            mailSender.send(mailMessage);
            LOGGER.info("email was sent to {} successfully.", message.getTo());
        } catch(Exception e) {
            LOGGER.error(String.format("Message sending failed for [%s]", message), e);
        }
    }

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void setEmailSubject(String emailSubject) {
        this.emailSubject = emailSubject;
    }
   
}

=========================================================

The following class is merely a bean, which is used to hold the parameters of the message. It's feilds are self-explanatory.
=========================================================


package com.shyarmal.messaging.domain;


public class EmailMessage {

    private String to;
    private String from;
    private String text;
    private String cc;
    private String correlationId;

    public EmailMessage(String to, String from, String text) {
        this.to = to;
        this.from = from;
        this.text = text;
    }
   
    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getCc() {
        return cc;
    }

    public void setCc(String cc) {
        this.cc = cc;
    }

    @Override
    public String toString() {
        return String.format("message: to[%s], from[%s], text[%s]",
                to, from, text);
    }

}

=========================================================

EmailClient can be used as follows.
=========================================================
String emailText = "This is my email body";
EmailMessage eMessage = new EmailMessage("abc@gmail.com", "xyz@gmail.com", emailText);
emailClient.send(eMessage) ; // suppose emailClient is an instance of EmailClient

=========================================================

Required properties of the mailSender are set through Spring as follows. The properties are obtained from a file, mailing.properties. It's contents are further down in the post.
=========================================================

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"
    p:host="${mail.sender.host}"
    p:port="${mail.sender.port}"
    p:username="${mail.sender.username}"
    p:password="${mail.sender.password}"
    p:protocol="${mail.sender.protocol}"
    p:javaMailProperties-ref="mailProperties"/>

<bean id="emailClient" class="com.shyarmal.messaging.EmailClient"
    p:mailSender-ref="mailSender"
    p:emailSubject="${email.subject}"/>

<util:properties id="mailProperties">
        <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
        <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
        <prop key="mail.smtp.quitwait">${mail.smtp.quitwait}</prop>
</util:properties>

<context:property-placeholder location="classpath:mailing.properties"/>
=========================================================

mailing.properties contents 
=========================================================
email.subject = my email subject
mail.sender.host = smtp.gmail.com
mail.sender.port = 587
mail.sender.username =xxxxxxxx@xxxx.xxx
mail.sender.password = xxxxxx@xxxxx
mail.sender.protocol = smtp
mail.smtp.auth = true
mail.smtp.starttls.enable = true
mail.smtp.quitwait = false

thanks,
Shyarmal.

Saturday, July 9, 2011

Injecting enums to a map - spring

      Assume an enum class MyEnum is to be used as keys of a java.util.Map and injected in the spring configuration file. This can be done as follows;

package src.shyarmal.eg;

public enum MyEnum {
          A, B, C, D
}

The above enum can be injected to a Map in spring;

<util:map id="myMap" key-type="src.shyarmal.eg.MyEnum">
      <entry key="A" value="value a" />
      <entry key="B" value="value b" />
      <entry key="C" value="value c" />
      <entry key="D" value="value d" />

</util:map>

This map can be injected to a class.

package src.shyarmal.eg;

public class MyClass {

     private Map<MyEnum, String> myMap;

     public void doIt() {
          //do something  ....  
    }
  
    public void setMyMap(Map<MyEnum, String> myMap) {
         this.myMap = myMap;    
   }
}

Spring configuration of MyClass.

<bean id="myClass" class="src.shyarmal.eg.MyClass">
     <property name="myMap" ref="myMap">
</bean>


thanks,
Shyarmal