Saturday 31 March 2012

EHCache Basics

Ehcache is easy and very powerful object caching system.
First step is to download the distribution. From the archive you need the
  • ehcache-core-2.3.1.jar - jar file contains everything that is need to use ehcache.
  • ehcache.xsd - schema for the ehcache configuration file.

First you need to create configuration file ehcache.xml.
ehcache.xml
  
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">

    <!-- Specify cache storage location -->
    <diskStore path="/tmp/opencourzesupport/cache"/>
    <defaultCache
      maxElementsInMemory="0"
      eternal="false"
      timeToIdleSeconds="0"
      timeToLiveSeconds="0"
      overflowToDisk="false" />
    <cache name="MyCache"
           maxElementsInMemory="0"
           maxElementsOnDisk="5000"
           eternal="false"
           overflowToDisk="true"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off"
            />
</ehcache>

Configuration defines storage directory and cache with name "MyCache".
You need to specify default cache too, else it will throw exception.
Let's define the object that we are going to put into cache:
 
package com.opensourzesupport.ehcache.model;
/**
 *
 * @author prasobh
 */
public class Student {
    private String name;
    private int age;
    private String address;
    private long id;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }   
    
    @Override
    public String toString() {
        return "Student{" + "name=" + name + ", age=" + age + ", address=" + address + ", id=" + id + '}';
    }
}

This is java code that implements caching logic:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.opensourzesupport.ehcache;

import com.opensourzesupport.ehcache.model.Student;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

/**
 *
 * @author prasobh
 */
public class TestCache {

    public TestCache() {
        CacheManager cm = new CacheManager(this.getClass().getResourceAsStream("/com/opensourzesupport/ehcache/resource/ehcache.xml"));
        Cache cache = cm.getCache("MyCache");
        Student student = new Student();
        student.setId(1);
        student.setName("Prasobh.K");
        student.setAge(26);
        student.setAddress("OpenSourzeSupport");
         cache.put(new Element(1, student));
        Student cachedBean = (Student) cache.get(1).getObjectValue();

        System.out.println("Model from cacahe : " + cachedBean);
    }

    public static void main(String[] args) {
        new TestCache();

    }
}

Output :
Model from cacahe :  Student{name=Prasobh.K, age=26, address=OpenSourzeSupport, id=1}

Saturday 24 March 2012

JAXB 2.0 Tutorial

JAXB (Java Architecture for XML Binding ) is a Java standard that defines how Java objects can be converted to XML (Marshalling in jaxb terms) and  the other way around (UnMarshalling).



No extra jaxb libraries are required if you are using JDK1.6 or above, because JAXB is bundled in JDK 1.6.
Note : -For JDK < 1.6, download JAXB from here, and puts “jaxb-api.jar” and “jaxb-impl.jar” on your project classpath.
JAXB uses annotations to indicate the central elements.




@XmlRootElement(namespace = "namespace")  : Define the root element for a XML tree
@XmlType(propOrder = { "field2", "field1",.. }): Allows to define the order in which the fields are written in the XML file
@XmlElement(name = "newName"): Define the XML element which will be used. Only need to be used if the newName is different than the javabean name
@XmlAccessorType(XmlAccessType.FIELD) :Used to show the feilds in xml file
@XmlAttribute  : Define the attribute for an XML element 


Lets analyse a Student model .

Student.java


package com.opensourzesupport.jaxb.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author prasobh 


*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)


/ /If you want you can define the order in which the fields are written
// Optional
@XmlType(propOrder = { "age", "name", "address"})


public class Student {

    @XmlAttribute
    private long id;


// If you like the variable name, e.g. "name", you can easily change this
// name for your XML-Output:
    @XmlElement(name="studentname")
    private String name;
    @XmlElement
    private int age;
    @XmlElement
    private Address address;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" + "id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + '}';
    }
}


Address.java
package com.opensourzesupport.jaxb.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author prasobh
 */



public class Address {

    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" + "address=" + address + '}';
    }    
}





Now lets write a helper class for converting object to xml and vise versa.

Convertor.java
package com.opensourzesupport.jaxb.codec;

import com.opensourzesupport.jaxb.constants.JAXBContants;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

/**
 *
 * @author prasobh
 */
public class Convertor {

    JAXBContext jAXBContext = null;

    public void init() throws JAXBException {
        jAXBContext = JAXBContext.newInstance(JAXBContants.JAXB_CLASSES);
    }

    public String encode(Object obj) throws JAXBException {
        StringWriter writer = new StringWriter();
        jAXBContext.createMarshaller().marshal(obj, writer);
        return writer.toString();

    }

    public Object decode(String xml) throws JAXBException {
        StringReader reader = new StringReader(xml);
        return jAXBContext.createUnmarshaller().unmarshal(reader);
    }
}



JAXBContants class holds all the requred modesl for marshalling and unmarshalling

JAXBContants.java

package com.opensourzesupport.jaxb.constants;

import com.opensourzesupport.jaxb.model.Student;

/**
 *
 * @author prasobh
 */



public class JAXBContants {
    public static Class[] JAXB_CLASSES = {Student.class};
} 

Let's test our application.

TestJAXB .java
package com.opensourzesupport.jaxb;

import com.opensourzesupport.jaxb.codec.Convertor;
import com.opensourzesupport.jaxb.model.Address;
import com.opensourzesupport.jaxb.model.Student;

/**
 *
 * @author prasobh
 */
public class TestJAXB {
    public static void main(String[] args) {
        Student student = new Student();
        Address address = new Address();
        student.setName("Prasobh K");
        student.setId(System.nanoTime());
        student.setAge(26);
        address.setAddress("OpenSourzeSupport");
        student.setAddress(address);
        Convertor convertor = new Convertor();
        try {
            convertor.init();
            String xml = convertor.encode(student);
            System.out.println("Encode value ["+ xml +"]");
            Object studObj = convertor.decode(xml);
            System.out.println("Decoded student obj["+studObj+"]");
        } catch (Exception e) {
            e.printStackTrace();;
        }
        
    }
}



Output

Encode value :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student id="2441156348740">
    <studentname>Prasobh K</studentname>
    <age>26</age>
    <address>
        <address>OpenSourzeSupport</address>
    </address>
</student>

Decoded student obj[
Student{id=2441156348740, name=Prasobh K, age=26, address=Address{address=OpenSourzeSupport}}
]
Thats it.Enjoy coding..

Friday 23 March 2012

Using Calendar in Quartz Scheduler for Job fire skip


Quartz Calendars can be used by the scheduler to block of a list of days, range of time or particular days of the year/month/week from the scheduler fire timings. Attaching a calendar onto a trigger ensures that the trigger does not get fired on date/time as defined by the Calendar.
There are different types of Calendar already available or a new Calendar can be using the Quartz calendar interface. List of available calendars on quartz can be got here
The below sample shows the use of one such Calendar – WeeklyCalendar that disables job fire on weekends – perfect for our Scheduler application. The method of using it is to first create an object of the WeeklyCalendar and then add it onto the scheduler along with a string name through which it can be further referenced. Then, this string name is used as an argument in setting the calendar name for the trigger.
package com.opensourzesupport.schedule;

import com.opensourzesupport.schedule.jobs.MyJob;
import com.opensourzesupport.schedule.listeners.MyJobListener;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.WeeklyCalendar;

/**
 *
 * @author prasobh
 */
public class Schedular {

    public Schedular() {
        try {
            //Create the weekly calendar object - 
            //This by default handles disaabling job fire on weekends so no need
            //to explicitly set
            WeeklyCalendar weeklyOff = new WeeklyCalendar();
            //AnnualCalendar annualCalendar = new AnnualCalendar();            
            //MonthlyCalendar monthlyCalendar = new MonthlyCalendar();
            //monthlyCalendar.setDayExcluded(5, true);
            //example of adding an excluded day of the week - This excludes fridays from job firing schedule
            weeklyOff.setDayExcluded(Calendar.FRIDAY, true);
            Properties prop = new Properties();
            prop.setProperty("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore");
            prop.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
            prop.setProperty("org.quartz.threadPool.threadCount", "4");
            SchedulerFactory schdFact = new StdSchedulerFactory(prop);
            Scheduler schd = schdFact.getScheduler();
            //add the Calendar object created to the scheduler with a string identifier to it
            schd.addCalendar("weeklyOff", weeklyOff, false, true);
            schd.start();
            JobDetail jobDetails = new JobDetail("myjob", Scheduler.DEFAULT_GROUP, MyJob.class);
            Trigger trigger = TriggerUtils.makeMinutelyTrigger();
            trigger.setName("every minutes");
            //set the calendar associated with the trigger
            trigger.setCalendarName("weeklyOff");
            trigger.getJobDataMap().put("auth_name", "Prasobh");
            trigger.setStartTime(new Date());
            schd.addJobListener(new MyJobListener());
            jobDetails.addJobListener("My Job");
            schd.scheduleJob(jobDetails, trigger);
            System.out.println(schd.getSchedulerName());
schd.start();
          
    } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) {
        new Schedular();
    }
}
 


Cron Trigger,Jobs and Expressions in Quartz Scheduler


Cron triggers in Quartz can be used to schedule a job based on an expression ( more like a reg-ex) defining when precisely the job execution is allowed. The cron trigger can be used to schedule a job only on specific days of month, or a definite time range for specific days etc. The cron expression is a string which comprises of 7 elements of which 6 are mandatory.
Cron expression involves 6 or 7 fields in a string separated by whitespace. The fields and their allowed values are (individually or as a range) –
Seconds -> 0-59
Minutes -> 0-59
Hours -> 0-23
Day of month -> 1-31
Month –> 1-12 or JAN-DEC
Day of week -> 1-7 or SUN-SAT
And the optional field of
Year -> 1970-2099
Along with the literal values for the fields, a cron expression also allows a few general and specific ( for particular fields ) wildcard entries to be used in the string. General wildcard entries include “*” signifying any value from the allowed range of values, “,” signifying combination of values for example 1,2,3 for day of month, the range specifier “-“, the “/” wildcard entry, which signifies increment. For example using 2/10 in the minutes field signifies that the job has to be fired every 10th minute starting from the second minute of the hour i.e., 2nd ,12th ,22nd ,32nd ,42nd ,52nd minute of the hour and the “?” literal which signifies that there is no specific value. The “?” literal is used especially in cases of day of week and day of month where one might influence the other. For example, to specify all weekdays of a month, the “?” literal can be used in the field day of month and MON-FRI in day of week field so that cron is fired on all weekdays irrespective of the date
Some of the special wildcard entries which are specific to “day of month” field are L and W –where L specifies the last day of the month and W signifies the weekday closest to the given day, for example 10W specifies the weekday after 10th if the 10th falls on a weekend else the day itself. Please note that the usage of W does not spill-over to the next month, in that, if, 30W is specified then, if 30 and 31 are weekend then, the job is not executed on 1st of the next month but, is executed on the weekday next to 30th of the coming month.
The other wildcard entries are L and # used in the “day of week” field. The “L” entry has the same meaning here, in that, it signifies the last day of the week (ie., 7 or SAT ) also, it can be additionally used with a value from 1-7 which makes it the last particular day of the month – for example, 5L specifies the last Thursday of the month. The # wildcard entry on the other hand is used to specify the nth day of the month – for example 3#2 means second Tuesday of the month ( 3 -> Tuesday and #2 -> position in the month )
Let us make a scheduler application, so that the job is scheduled only for the weekdays along with a break for Christmas –
Schedular.java
package com.opensourzesupport.schedule;
import com.opensourzesupport.schedule.jobs.MyJob;
import com.opensourzesupport.schedule.listeners.MyJobListener;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.AnnualCalendar;

/**
 *
 * @author prasobh
 */
public class Schedular {

    public Schedular(){
         try {
            //Create the annual calendar object - to add Christmas holiday to our Alarm Job fire exception

            AnnualCalendar holidays = new AnnualCalendar();

            Calendar christmas = new GregorianCalendar(2011, 11, 25);

            holidays.setDayExcluded(christmas, true);

            Properties prop = new Properties();

            prop.setProperty("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore");

            prop.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");

            prop.setProperty("org.quartz.threadPool.threadCount", "4");

            SchedulerFactory schdFact = new StdSchedulerFactory(prop);

            Scheduler schd = schdFact.getScheduler();

            //add the Calendar object created to the scheduler with a string identifier to it

            schd.addCalendar("holidays", holidays, false, true);

            schd.start();

            JobDetail jobDetails = new JobDetail("myjob", Scheduler.DEFAULT_GROUP, MyJob.class);

            //Define a cron job such that the job executes every weekday at 06:00

            CronTrigger trigger = new CronTrigger("myjobtrigger", Scheduler.DEFAULT_GROUP, "0 0 6 ? * MON-FRI *");

            //set the calendar associated with the trigger

            trigger.setCalendarName("holidays");

            trigger.getJobDataMap().put("auth_name", "Prasobh");

            trigger.setStartTime(new Date());

            schd.addJobListener(new MyJobListener());

            jobDetails.addJobListener("My Job");

            schd.scheduleJob(jobDetails, trigger);

            System.out.println(schd.getSchedulerName());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Schedular();
    }
}

MyJob.java

package com.opensourzesupport.schedule.jobs;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 *
 * @author prasobh
 */
public class MyJob  implements Job{

    @Override
    public void execute(JobExecutionContext jec) throws JobExecutionException {
        System.out.println("executing my my job");
    }
    
}

 In the above program, the line
CronTrigger t = new CronTrigger("alarmtrigger", Scheduler.DEFAULT_GROUP, "0 0 6 ? * MON-FRI *"); 

creates a new cron-trigger that is scheduled for every weekday at 0600 hrs. The string “0 0 6 ? * MON-FRI *” specifies -
0 – 0th second
0 – 0th minute
6 – 6 AM hours
? – no specific day of the month
“*” – all months
MON-FRI – only weekdays
“*” – any year

 Note:- While create a schedule JobDetail name and JobDetails Group should be uniqueCronTriggername and  CronTrigger  Group should be unique 


Tuesday 13 March 2012

JDBCJobStore in Quartz Scheduler

JDBCJobStore is a way of maintaining the quartz job details over a database via the JDBC. While the use of RAMJobStore indicates volatile storage of the quartz job details, a JDBCJobStore ensures that the information on the quartz jobs, triggers, calendars etc are available any time in case the system has a downtime and then can be rescheduled once the system is up.
A JDBCJobStore requires some database tables to be present in the data source defined for use of quartz. The sql queries for creating and populating the required tables is available under the docs/dbTables folder of the quartz distribution. The following example uses the MySQL database to schedule a job using the JDBCJobStore.
The file quartz.properties is used by the program to define the quartz properties -
Sample Program – file quartz.properties

#Skip Update Check
#Quartz contains an "update check" feature that connects to a server to
#check if there is a new version of Quartz available
org.quartz.scheduler.skipUpdateCheck: true

org.quartz.scheduler.instanceName =OZS_SCHEDULAR
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 4
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.threadPool.threadPriority = 5


#specify the jobstore used
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = false

#specify the TerracottaJobStore
#org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore
#org.quartz.jobStore.tcConfigUrl = localhost:9510


#The datasource for the jobstore that is to be used
org.quartz.jobStore.dataSource = myDS

#quartz table prefixes in the database
org.quartz.jobStore.tablePrefix = qrtz_
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.isClustered = false

#The details of the datasource specified previously
org.quartz.dataSource.myDS.driver =com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL =jdbc:mysql://localhost:3306/test
org.quartz.dataSource.myDS.user =root
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections = 20

#Clustering
#clustering currently only works with the JDBC-Jobstore (JobStoreTX
#or JobStoreCMT). Features include load-balancing and job fail-over
#(if the JobDetail's "request recovery" flag is set to true). It is important to note that
# When using clustering on separate machines, make sure that their clocks are synchronized
#using some form of time-sync service (clocks must be within a second of each other).
#See http://www.boulder.nist.gov/timefreq/service/its.htm.
# Never fire-up a non-clustered instance against the same set of tables that any
#other instance is running against.
# Each instance in the cluster should use the same copy of the quartz.properties file.

org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000

#Each server must have the same copy of the configuration file.
#auto-generate instance ids.
org.quartz.scheduler.instanceId = AUTO

#Note :
#If a job throws an exception, Quartz will typically immediately
#re-execute it (and it will likely throw the same exception again).
#It's better if the job catches all exception it may encounter, handle them,
#and reschedule itself, or other jobs. to work around the issue.


  MyJob .java
package com.opensourzesupport.schedule.jobs;
 
import org.quartz.Job;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;


/**

 *

 * @author prasobh

 */


public class MyJob  implements Job{


    @Override

    public void execute(JobExecutionContext jec) throws JobExecutionException {

        System.out.println("executing my my job");

    }   

}



Schedule.java
package com.opensourzesupport.schedule;

import com.opensourzesupport.schedule.jobs.MyJob;
import com.opensourzesupport.schedule.listeners.MyJobListener;
import java.util.Date;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;

/**
 *
 * @author prasobh
 */
public class Schedular {

    public Schedular() {
        try {
            SchedulerFactory schdFact = new StdSchedulerFactory("quartz.properties");
            Scheduler schd = schdFact.getScheduler();
            schd.start();

            JobDetail jd = new JobDetail("alarmjob", Scheduler.DEFAULT_GROUP, MyJob.class);
            Trigger t = TriggerUtils.makeDailyTrigger("alarmtrigger", 06, 00);
            t.getJobDataMap().put("auth_name", "Vageesh");
            t.setStartTime(new Date());
            schd.addJobListener(new MyJobListener());
            jd.addJobListener("Alarm gone");
            schd.scheduleJob(jd, t);
            schd.start();
            System.out.println(schd.getSchedulerName());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Schedular();
    }
}


On successful fire of job, it can be observed that the job details and 
data blob details are updated in the tables of the database
 

Rescheduling Job

Rescheduler.java


package com.opensourzesupport.schedule;


import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;

/**
 *
 * @author prasobh
 */
public class Reschedular {

    public 
Reschedular() {

        String[] triggerGrps;
        String[] triggers;
        try {

            SchedulerFactory sf = new StdSchedulerFactory("quartz.properties");
            Scheduler sd = sf.getScheduler();
            sd.start();
            triggerGrps = sd.getTriggerGroupNames();
            for (String stTriggerGrp : triggerGrps) {
                triggers = sd.getTriggerNames(stTriggerGrp);
                for (String stTrigger : triggers) {
                    Trigger quartzTrigger = sd.getTrigger(stTrigger, stTriggerGrp);
                    System.out.println("Trigger Name : " + stTrigger);
                    System.out.println("Trigger Group Name: " + stTriggerGrp);
                    sd.rescheduleJob(stTrigger, stTriggerGrp, quartzTrigger);
                }
            }
          
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Reschedular();
    }
}

 

 

 

Thursday 1 March 2012

High Level Requirements Gathering Questions for New Development Projects

Determine Business Objectives
    1.    What are your goals in developing this system?
    2.    Who are the key stakeholders and users? Do their goals differ? If so, how?
    3.    How do the system goals map to business goals?
    4.    What is the most important business goal of the system?
    5.    Will the system change the way you are doing things now?
    6.    Will the system help you be more efficient?  How?
    7.    What are the system deliverables? 
    8.    What will the new system accomplish that is not currently accomplished manually or with other systems?
    9.    What will the new system do?

Determine Future Needs
    1.    What business requirements will this system address?
    2.    What information do you need from this system that you don’t have now? 
    3.    Is any of this data currently captured in any other corporate system?
    4.    How would you like to see this information?  
    5.    What functionality do you need from the system?
6.        Is the data and/or functionality shared by other (many) business areas?  If so, which?
7.        If the reports were dynamic, what would they do differently?
8.        How much historical information is required?

Determine Current Problems
    1.    What are the current problems facing without the system today?
    2.    What problems should this system solve?
    3.    Do you have to do things manually that you would like to automate?
    4.    Do you have performance problems that need to change?
    5.    Do you have functional limitations that you’d like to change?
6.        Are you using packages that force you to constrain your business functionality to the boundaries of the package?
7.        Which reports do you currently use?  What data on the report is important?  How do you use the information?
8.        Are there specific bottlenecks to getting at information?
9.        How do you analyze the information you currently receive?  What type of data is used?  How do you currently get the data?  How often do you get new data?
10.    What type of ad hoc analysis do you typically perform?  Who requests ad hoc information?  What do you do with the information?

Determine System Users
   1.    Who will be using the system?
   2.    What are the titles and roles of the people who will use the system?
   3.    What are their levels of expertise?

Determine Criteria for Success
   1.    What is most important for success of the application?
   2.    What do we need to accomplish to make this project successful?
   3.    What do we need to change to make this project successful?
   4.    What buy-in do we need?
   5.    Are we lacking any critical elements such as budget, resource allocation, or support?
   6.    What are training considerations for developers and users?

Assumptions
    1.    List assumptions

Issues
    1.    List open issues, responsible parties and resolution date