Friday, December 12, 2014

Quartz Scheduler and Cron Job/Trigger in Spring

Quartz Scheduler and CRON job in Spring Application

Steps to implement Quartz Scheduler in Spring application.

Step 1. Include the following dependency inclusion into your pom.xml


<!-- Quartz framework dependencies -->

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.1.3</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-oracle</artifactId>
    <version>2.1.3</version>
</dependency>


Step 2:  Write scheduler job class



package ****.util;

import java.util.Date;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * information about cim renew reminder job
 * @author velmurugan pousel
 * @created on Dec 11, 2014
 *
 */
public class CIMRenewReminderJob extends QuartzJobBean  {

    private static final Log LOG = LogFactory.getLog(CIMRenewReminderJob.class);
   
    private CIMParametersService cIMParametersService;
   
    @Override
    protected void executeInternal(JobExecutionContext context)
            throws JobExecutionException {

        SchedulerContext schedulerContext;
        try {
            if (LOG.isDebugEnabled()) {
                LOG.info("Entering into method executeInternal of class SchoolScoreFTPJobDetail");
            }

            schedulerContext = context.getScheduler().getContext();

            BeanFactory beanFactory = (BeanFactory) schedulerContext
                    .get("applicationContext");

            if (cIMParametersService == null) {
                cIMParametersService = (CIMParametersService) beanFactory
                        .getBean("cIMParametersService");

            }

            sendRenewReminders();

        } catch (Exception e) {
            LOG.error(" Error on CIMRenewReminderJob ", e);
        }

        if (LOG.isDebugEnabled()) {
            LOG.info("Exiting from method executeInternal of class CIMRenewReminderJob");
        }

    }
   
    /**
     * send out the CIM renew reminder notifications
     *
     * @return true or false
     */
    private boolean sendRenewReminders() {

        LOG.info(" ################## CIM Renew Rimnder job triggered on " + new Date());

        return false;
    }

}


Step 3:   Define the job details in xml file along with the cron trigger details to trigger this job based on the expression.


applicationContext-schedular.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/util
                        http://www.springframework.org/schema/util/spring-util-3.1.xsd
                        http://www.springframework.org/schema/jee
                        http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

   
    <bean id="scheduler"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
        lazy-init="false">
        <property name="dataSource" ref="dataSource" />
        <property name="overwriteExistingJobs" value="true" />
        <property name="autoStartup">
            <value>true</value>
        </property>
        <property name="jobFactory">
            <bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory" />
        </property>
        <property name="applicationContextSchedulerContextKey">
            <value>applicationContext</value>
        </property>
        <property name="waitForJobsToCompleteOnShutdown">
            <value>true</value>
        </property>
        <property name="transactionManager" ref="transactionManager" />
        <property name="quartzProperties">
            <props>
                <prop key="org.quartz.scheduler.classLoadHelper.class">org.quartz.simpl.CascadingClassLoadHelper</prop>
                <prop key="org.quartz.scheduler.instanceName">MCATSRSScheduler</prop>
                <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
                <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
                <prop key="org.quartz.threadPool.threadCount">20</prop>
                <prop key="org.quartz.threadPool.threadPriority">5</prop>
                <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
                <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>               
                <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
                </prop>
                <prop key="org.quartz.jobStore.useProperties">false</prop>
                <prop key="org.quartz.jobStore.selectWithLockSQL">SELECT * FROM {0}LOCKS WHERE SCHED_NAME = {1} AND
                    LOCK_NAME = ? FOR UPDATE</prop>
                <prop key="org.quartz.jobStore.isClustered">true</prop>
                <prop key="org.quartz.jobStore.clusterCheckinInterval">20000</prop>
            </props>
        </property>
       
        <property name="jobDetails">
            <list>
                <ref bean="renewReminderJob" />           
            </list>
        </property>
 
        <property name="triggers">
            <list>   
                <ref bean="renewReminderTrigger" />     
            </list>
        </property>
    </bean>
   
    <!--     JOB CONFIGURATION FOR FTP JOB  -->        
       
    <bean id="renewReminderTrigger"
        class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="renewReminderJob" />
      <!--<property name="cronExpression" value="0 30 10 ? * *" />  -->
          <property name="cronExpression" value="0 0/10 * ? * MON-FRI" />
          <!-- this job would be triggered on every 10 mins ->
    </bean>    
        
    <bean name="renewReminderJob"
        class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass"
            value="org.*.cim.service.subs.util.CIMRenewReminderJob" />
        <property name="group" value="REMINDER_JOB" />
    </bean>
         
   
</beans>

Step4: Include your applciationContext-schedular.xml in applicationContaxt.xml



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd
                        http://www.springframework.org/schema/jee
                         http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

    <context:component-scan base-package="org.*.subs" />

    <jee:jndi-lookup id="pouselEnv" jndi-name="cell/persistent/misc/pouselEnv" default-value="localhost" />

     <jee:jndi-lookup id="servicesUrl" jndi-name="cell/persistent/misc/servicesUrl" default-value="http://services2.development.pouselv.org"/>

     <bean id="envProperties" class="org.pouselv.commons.spring.util.JNDIPropertiesFactoryBean">
        <property name="location" ref="pouselEnv"/>
     </bean>


    <import resource="applicationContext-resources.xml" />
    <import resource="applicationContext-security.xml" />
    <import resource="applicationContext-hibernate.xml" />
 <import resource="applicationContext-services.xml" />   
      

   <import resource="applicationContext-scheduler.xml" />
   
   
</beans>

Step 4: Create the following tables in your DB schema to store and keep track of the quartz scheduler and job details.



DROP TABLE QRTZ_SIMPLE_TRIGGERS;
DROP TABLE QRTZ_CRON_TRIGGERS;
DROP TABLE QRTZ_SIMPROP_TRIGGERS;
DROP TABLE QRTZ_CALENDARS;
DROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE QRTZ_FIRED_TRIGGERS;
DROP TABLE QRTZ_SCHEDULER_STATE;
DROP TABLE QRTZ_LOCKS;
DROP TABLE QRTZ_TRIGGERS;
DROP TABLE QRTZ_JOB_DETAILS;

CREATE TABLE QRTZ_JOB_DETAILS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME  VARCHAR2(200) NOT NULL,
    JOB_GROUP VARCHAR2(200) NOT NULL,
    DESCRIPTION VARCHAR2(250) NULL,
    JOB_CLASS_NAME   VARCHAR2(250) NOT NULL,
    IS_DURABLE VARCHAR2(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR2(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR2(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    JOB_NAME  VARCHAR2(200) NOT NULL,
    JOB_GROUP VARCHAR2(200) NOT NULL,
    DESCRIPTION VARCHAR2(250) NULL,
    NEXT_FIRE_TIME NUMBER(13) NULL,
    PREV_FIRE_TIME NUMBER(13) NULL,
    PRIORITY NUMBER(13) NULL,
    TRIGGER_STATE VARCHAR2(16) NOT NULL,
    TRIGGER_TYPE VARCHAR2(8) NOT NULL,
    START_TIME NUMBER(13) NOT NULL,
    END_TIME NUMBER(13) NULL,
    CALENDAR_NAME VARCHAR2(200) NULL,
    MISFIRE_INSTR NUMBER(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
      REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    REPEAT_COUNT NUMBER(7) NOT NULL,
    REPEAT_INTERVAL NUMBER(12) NOT NULL,
    TIMES_TRIGGERED NUMBER(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    CRON_EXPRESSION VARCHAR2(120) NOT NULL,
    TIME_ZONE_ID VARCHAR2(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (         
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 NUMBER(10) NULL,
    INT_PROP_2 NUMBER(10) NULL,
    LONG_PROP_1 NUMBER(13) NULL,
    LONG_PROP_2 NUMBER(13) NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME  VARCHAR2(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR2(200) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR2(95) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    INSTANCE_NAME VARCHAR2(200) NOT NULL,
    FIRED_TIME NUMBER(13) NOT NULL,
    PRIORITY NUMBER(13) NOT NULL,
    STATE VARCHAR2(16) NOT NULL,
    JOB_NAME VARCHAR2(200) NULL,
    JOB_GROUP VARCHAR2(200) NULL,
    IS_NONCONCURRENT VARCHAR2(1) NULL,
    REQUESTS_RECOVERY VARCHAR2(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
  (
   SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR2(200) NOT NULL,
    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,
    CHECKIN_INTERVAL NUMBER(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME  VARCHAR2(40) NOT NULL,
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);

commit;




Reference:

CRON Expressions  



The Cron-Expressions are strings which are used for configuring the instances of CronTrigger. The Cron-Expressions made up of following sub-expressions that performs individual works according to it's schedule and that is separated by the white-space. :
  1. Seconds
  2. Minutes
  3. Hours
  4. Day-of-Month
  5. Month
  6. Day-of-Week
Example: The Cron-expression string is "0  0  10  ?  *  SUN" that means "every Sunday at 10 am". This example reads only the "SUN" from weekday and replaces to all weekday.
The Wild-cards ('* ' character) that can be used for inserting the every possible value of this field. The '*' character is used in the "Month" field that means "every month" and "Day-Of-Week" field means "every day of the week".
All fields have some specific values that are specified by us. Such as the numbers 0 to 23 for hours, 0 to 59 that is used for minutes and seconds, 0 to 31 for Day-of-Month but here, we should more careful about how many day are used in a month. Months have the specified values between 0 to 11, for this we will use the some string as like: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Similarly, the Days-of-week has specified values between 1 to 7. Here 1 for Sunday, 2 for Monday, 3 for Tuesday,....... so on. But here we will use the some string for this like: SUN, MON, TUE, WED, THU, FRI and SAT.
The Cron-Expressions are used the '/' character for increments to specify values. If we will put "0/10" in the seconds field that means every 10 seconds will start at second zero and if we will put "0/20" in the Minutes field then it will simply fires every 20 minutes.
The Cron-Expressions are also used the '?' character that allows for the day-of-month and day-of-week fields for specifying "no specific value".
The 'L' character, it is the short form of "last" that allows us for using the day-of -month and day-of-week fields. If we can use the value 'L' in the day-of-month field that means last day of the month like: 31 for January, 28 for February not the leap years. In case of day-of-week field that means "7 stands for SAT".
There are following example of expressions for specify the JavaDOC for CronTrigger:
1.Example: Write an expression to create a trigger that fires ever 10 minutes.
     "0  0/10  *  *  *  ?"
2.Example: Write an expression to create a trigger that fires every 10 minutes, at 10 seconds after the minute.
      "10  0/10  *  *  *  ?"
  (That means each firing after the 10 seconds interval like: 8:00:00am, 8:10:00am,8:20:00am etc.)
3.Example: Write an expression to create a trigger that fires at 9:30, 10:30, 11:30, 12:30 and 13:30 on every Sunday and Saturday.
      "0  30  9-13  ?  *  SUN, SAT"


Wednesday, October 1, 2014

Posting list of json objects from Extjs to Spring MVC

Posting list of json objects from Extjs to Spring MVC by using extjs editable grid




    var premedCompletedCourseworkGrid = new Ext.extend(
            Ext.grid.EditorGridPanel,
            {
                // plugins: [editor],
                stripeRows : true,
                columnLines : true,
                enableHdMenu : false,
                autoHeight : false,
                disableSelection : false,
                width : '100%',               
                clicksToEdit : 1,
                viewConfig : {
                    overflow : 'auto',
                    autoScroll : true

                },

                baseCls : 'user-premed-grid',
                store : premedCompletedCourseworkStore,
                title : "My Premedical Coursework ",
                columns : [ {
                    header : 'Course',
                    width : 240,
                    sortable : true,
                    dataIndex : 'course',
                    renderer : COMMON.renderCourse,                   
                    name : 'course'
                }, {
                    header : 'Lab?',
                    width : 150,
                    sortable : true,
                    dataIndex : 'lab',
                    name : 'lab',
                    align : 'center',
                    renderer : COMMON.renderLabDesc,
                    editor : new Ext.form.ComboBox({
                        typeAhead : true,
                        triggerAction : 'all',
                        transform : 'labExamOption',
                        lazyRender : true,
                        listClass : 'x-combo-list-small'
                    })
                }, {
                    header : 'Unit',
                    width : 150,
                    sortable : true,
                    dataIndex : 'units',
                    name : 'units',
                    renderer : COMMON.renderUnits,
                    align : 'center',
                    editor : new Ext.form.TextField()
                } , {
                    header : 'Unit Type',
                    width : 155,
                    sortable : true,
                    renderer : COMMON.renderUnitTypeDesc,
                    dataIndex : 'unitType',
                    name : 'unitType',
                    align : 'center',
                    editor : new Ext.form.ComboBox({
                        typeAhead : true,
                        triggerAction : 'all',
                        transform : 'unitTypeOption',
                        lazyRender : true,
                        listClass : 'x-combo-list-small'
                    })
                }

                ],
                tbar : [ {
                    xtype : 'common.saveImgButton',    //extjs button     defined below           
                    handler : function() {
                        try {
                                                       
                            var store =  new premedCompletedCourseworkGrid().getStore(); 
                           
                            if (store != null){
                           
                            // give only the modified rows data
                                var changedRecs = store.getModifiedRecords();
                                 var resultStatus = true;
                                 var data = [];
                                if (changedRecs != null && changedRecs.length > 0) {
                                    for ( var i = 0; i < changedRecs.length; i++) {
                                        var wamID = changedRecs[i].data.wamId;
                                        var course = changedRecs[i].data.course;
                                        var units = changedRecs[i].data.units;
                                        var unitType = changedRecs[i].data.unitType;
                                        var lab = changedRecs[i].data.lab;
                                        if (units != null && units >0){
                                             data.push({
                                                 wamId:wamID,
                                                 course:course,
                                                 lab:lab,
                                                 units:units,
                                                 unitType:unitType
                                             });
                                        }                                       
                                    }   

                                    var courseList = {preMedCourseList:data};
                                    // json structure is {"preMedCourseList":[{"wamId":1312,
                                       "course":course,"lab":'asd' ....},{}]}
                                    Ext.Ajax.request({
                                           url:'saveUserPreMedCourseWork1',                                          
                                           method: "POST",                                        
                                           headers: { 'Content-Type': 'application/json;charset=utf-8' },   
                                           jsonData:courseList,
                                           success: function(response, opts) {                                            
                                            try {
                                                //alert('reload');
                                                 premedCompletedCourseworkStore.reload();   
                                               
                                                var return_obj = Ext.decode(response.responseText);
                                                resultStatus = return_obj.success;                                               
                                            } catch (e) {
                                                resultStatus = false;                                               
                                                Ext.MessageBox.alert('Save premed course', "There was a problem
                                                saving pre med course. Please refresh your browser." + e.message);
                                            }                                              
                                        }
                                    }); 
                               
                                } else {
                                    return Ext.MessageBox.alert('Confirm Save',
                                            'Course details not modified');
                                }
                            }
                           
                        } catch (e){
                            return Ext.MessageBox.alert('Confirm Save',
                            'Course details not modified' + e.message);
                        }
                        
                    }
                } ]

            });
           
           
            //save image button
                COMMON.SaveImgButton = Ext.extend(Ext.Button, {
                    text : 'Save',
                    iconCls : 'edit',
                    scale : 'medium'
                });
   
            Ext.reg('common.saveImgButton', COMMON.SaveImgButton);




DTO Classes:



public class UserPreMedCourseList implements Serializable{

    /**
     *
     */
    private static final long serialVersionUID = 7948048144505511239L;
   
    List<UserPremedCourseworkDto>  preMedCourseList;

    public List<UserPremedCourseworkDto> getPreMedCourseList() {
        return preMedCourseList;
    }

    public void setPreMedCourseList(List<UserPremedCourseworkDto> preMedCourseList) {
        this.preMedCourseList = preMedCourseList;
    }
   
}




public class UserPremedCourseworkDto extends PremedCourseworkDto{

    private long wamId;
    private String schoolUnits;
    private String schoolUnitType;
    private String schoolLab;
   
    public long getWamId() {
        return wamId;
    }

    public void setWamId(long wamId) {
        this.wamId = wamId;
    }
   
    public String getSchoolUnitType() {
        return schoolUnitType;
    }

    public void setSchoolUnitType(String schoolUnitType) {
        this.schoolUnitType = schoolUnitType;
    }

    public String getSchoolUnits() {
        return schoolUnits;
    }

    public void setSchoolUnits(String schoolUnits) {
        this.schoolUnits = schoolUnits;
    }

    public String getSchoolLab() {
        return schoolLab;
    }

    public void setSchoolLab(String schoolLab) {
        this.schoolLab = schoolLab;
    }
}

public class PremedCourseworkDto {

    private String course;
    private String required;
    private String recommended;
    private String lab;
    private String unitType;
    private String units;
    private String ap;
    private String online;
    private String comm;
..
}

MVC Controller :



    @RequestMapping(value = "{schoolId}/saveUserPreMedCourseWork1", method = RequestMethod.POST)
    public @ResponseBody
    ExtResponse saveUserPreMedCourseWork1(
            @PathVariable("schoolId") Long schoolId,
            @RequestBody UserPreMedCourseList preMedCourseList ) {
        try {

            List<UserPremedCourseworkDto> courseList = preMedCourseList.getPreMedCourseList();
            for (UserPremedCourseworkDto workDto : courseList) {
                workDto.setWamId(securityService.getCurrentWamId());
           
             ///  business logic goes here

                 }  
               
            }

        } catch (Exception e) {
            Logger.getLogger(SchoolDetailsController.class).error("Error on User pre medical course work details save",e);
            return failure();
        }

        return success();
    }





Wednesday, September 10, 2014

File Retention or Cleanup in java

How to cleanup files from file store based on retention period

Sample Java Program:



public class McatSRSFileUtil {

     
     private static Logger logger = LoggerFactory.getLogger(McatSRSFileUtil.class); 
   
     private Date currDate = new Date(); 
     private String pathToBeExcluded = ""; 
     
     /**
      * Main method would be invioked by quartz job to clean up the file which is older than 90 days
      * 
      * @throws Exception
      */ 
    public void processFileRetention(String srcDir, int retentionPeriod)
            throws Exception {
        logger.info("HOUSE KEEPING PROCESS - START");

        executeFileRetention(new File(srcDir), retentionPeriod);

        logger.info("HOUSE KEEPING PROCESS - COMPLETED");
    }
     
     /**
      * DELETE FILES OLDER THAN SPECIFED RETENTION PERIOD
      * 
      * @param deleteDir
      * @param retentionPeriod
      * @throws IOException
      */ 
    private void executeFileRetention(File deleteDir, int retentionPeriod)
            throws IOException {
        if (!deleteDir.exists()) {
            logger.warn("SKIP RETENTION... INVALID DIRECTORY TO DELETE FILE FROM -"
                    + deleteDir);
            return;
        }

        if (retentionPeriod == 0) {
            logger.warn("SKIP RETENTION... RETENTION PERIOD NOT SPECIFIED");
            return;
        }

        logger.info("CHECKING FOR OLD FILES IN DIR - "
                + deleteDir.getCanonicalPath());

        File[] dirList = deleteDir.listFiles();
        if (dirList.length == 0) {
            logger.info("NO FILES FOUND IN " + deleteDir.getCanonicalPath());
            return;
        }
        for (File file : dirList) {
            logger.trace("processing file:" + file);
            if (file.isDirectory()) {
                // DO NOT DELETE DIRECTORIES!!!!
                // RECURSIVELY CHECK SUB-DIRECTORIES FOR OLDER FILES
                executeFileRetention(file, retentionPeriod);
            } else if (file.isFile()) {
                // TODO CHEK FOR FILENAME PATTERN
                if (isFileOld(file, retentionPeriod)) {
                    deleteFile(file);
                }
            }
        }

    }
     
     /**
      * 
      * @param file
      *            file to be verified
      * @param retentionPeriod
      *            number of days to retain files
      * @return
      * @throws IOException
      */ 
     private boolean isFileOld(File file, int retentionPeriod) 
       throws IOException { 
      Date lastModifiedDate; 
      lastModifiedDate = new Date(file.lastModified()); 
      logger.trace(file + " last modified on " + lastModifiedDate); 
      int diffInDays = getDifferenceInDays(currDate, lastModifiedDate); 
      logger.trace("DIFF IN DAYS:" + diffInDays); 
     
      if (diffInDays > retentionPeriod) { 
       logger.trace(file.getCanonicalPath() + " IS OLD. DAYS-" 
         + diffInDays); 
       return true; 
      } 
      return false; 
     } 
      
     
     /**
      * DELETE SPECIFIED FILE
      * 
      * @param file
      *            file to be deleted
      * @throws IOException
      */ 
     public void deleteFile(File file) throws IOException { 
      String strCanonicalPath = file.getCanonicalPath(); 
      logger.debug("DELETING FILE " + strCanonicalPath); 
      // DO NOT DELETE ANY DIRECTORIES 
      if (!file.exists() || !file.isFile()) { 
       logger.error("INVALID FILE " + strCanonicalPath); 
       return; 
      } 
      boolean deleteStatus = file.delete(); 
      if (!deleteStatus) { 
       logger.error("FAILED TO DELETE FILE " + strCanonicalPath); 
      } 
     } 
     
     /**
      * derive file name to be used in tar. basically removes the directory path.
      * 
      * @param file
      * @return file name to be used in tar
      * @throws IOException
      */ 
     private String getFileName(File file) throws IOException { 
      // filename to be used in tar 
      String strCanonicalPath = file.getCanonicalPath(); 
      String fileName = ""; 
      // INDEX OF SRC 
      int index = strCanonicalPath.indexOf(pathToBeExcluded); 
      if (index >= 0) { 
       fileName = strCanonicalPath.substring(index 
         + pathToBeExcluded.length() + 1); 
      } 
      logger.trace("Name to be used in TAR-" + fileName); 
      return fileName; 
     } 
     
     // ************ COMMON UTILITY FUNCTIONS **************** 
     
     /**
      * CLOSE STREAM
      * 
      * @param stream
      * @throws IOException
      */ 
     private void close(Closeable stream) throws IOException { 
      try { 
       if (stream != null) { 
        stream.close(); 
       } 
      } catch (IOException ioEx) { 
       logger.warn("error closing stream", ioEx); 
       throw ioEx; 
      } 
     } 
   
     /**
      * This method checks whether the string is empty or not
      * 
      * @param strToCheck
      *            the string to be checked
      * @return it returns true if the string is null or empty, otherwise it
      *         returns false
      */ 
     public static boolean isStringEmpty(String strToCheck) { 
      if ((null == strToCheck) || strToCheck.trim().isEmpty()) { 
       return true; 
      } else { 
       return false; 
      } 
     } 
     
     /**
      * get the difference in days between two dates. considers DST.
      * 
      * @param date1
      *            the first date
      * @param date1
      *            the second date
      * 
      * @return int the difference in days (-ve if date1 < date2)
      * @throws ParseException
      */ 
     public static int getDifferenceInDays(Date date1, Date date2) { 
     
      Calendar cal1 = Calendar.getInstance(); 
      cal1.setTime(date1); 
     
      Calendar cal2 = Calendar.getInstance(); 
      cal2.setTime(date2); 
     
      // HAVE TO CONVERT BOTH THE INPUT DATES TO GMT TIMEZONE 
     
      // cal.getTimeZone().getOffset(cal.getTimeInMillis()) -> amount of time 
      // in milliseconds to add to GMT to get local time 
     
      long timeDiff = (cal1.getTimeInMillis() + cal1.getTimeZone().getOffset( 
        cal1.getTimeInMillis())) 
        - (cal2.getTimeInMillis() + cal2.getTimeZone().getOffset( 
          cal2.getTimeInMillis())); 
      return (int) TimeUnit.MILLISECONDS.toDays(timeDiff); 
     
      // long timeDiff = Math.abs(date1.getTime() - date2.getTime()); 
      // return (int) TimeUnit.MILLISECONDS.toDays(timeDiff); 
     } 
     
     /**
      * get current date
      * 
      * @param dateFormat
      * @return
      */ 
     public static String getCurrentDateTime(String dateFormat) { 
      Date today = new Date(); 
      DateFormat formatter = new SimpleDateFormat(dateFormat); 
      return formatter.format(today); 
     } 
     
    public static void main(String[] args) {
        String srcDir = "C:\\opt\\filestore\\appdata\\ci\\import";
        McatSRSFileUtil tester = new McatSRSFileUtil();
        try {
            tester.processFileRetention(srcDir, 60);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
   
}

Play HTML5 video in IE9

Play HTML5 <video>  in IE9




Step1 : Add the below meta tag in our html or jsp page.


            <meta http-equiv="X-UA-Compatible" content="IE=Edge"/> 

Step 2:  Add your video content into page


    <video width="320" height="240"
        src="<c:url value='/resources/video/text_video.mp3'/>" controls>
        Your browser does not support the video tag.
    </video>




Friday, September 5, 2014

Tomcat profile with JNDI datasource in RAD

Setup TOMCAT Profile with JNDI datasource inRAD

applicationContext-resources.xml


Step 1 :

<!-- This is a bean profile which can override items in the WebSphere profile for Tomcat like application servers. -->
    <!-- To activate this profile add -Dspring.profiles.active="tomcat" to your server startup, do not change the default profile setting in the web.xml -->
    <beans profile="tomcat">
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />

            <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
              <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
              <property name="url" value="jdbc:oracle:thin:@rac.development.aamc.org:1521/AMCAS" />
              <property name="username" value="CFRANCISCO[mcat_thx]" />
              <property name="password" value="Aamc#2012" />
              <property name="maxActive" value="10" />
              <property name="maxIdle" value="1" />
              <property name="maxWait" value="1000" />
              <property name="defaultAutoCommit" value="true" />
              <property name="poolPreparedStatements" value="true" />
              <property name="maxOpenPreparedStatements" value="100" />
              <property name="validationQuery" value="SELECT 1 from DUAL"/>
            </bean>
    </beans>

Step 2:

To activate this profile add -Dspring.profiles.active="tomcat" to your server startup or JVM arguement.