Showing posts with label batch. Show all posts
Showing posts with label batch. Show all posts

Friday, December 08, 2006

PDF Generation with Big Faceless Report Generator

Big Faceless Report Generator is a commercial Java API for generating PDF files from XML input. The report generator is built on the Big Faceless Java PDF library. It has a very easy to use API, but the one thing that I like most about it is, for it is more than a bargain for the price you pay for it. It easily out performs the open source PDF generators (iText and XSL FOP) and also has a lot of intersting features.

Skip to Sample Code
  • HTML-style Tables - auto-sized nested tables with full control over padding, margins and borders
  • Support for CSS2 Style sheets
  • Create inline graphs and charts with XML, direct from the database
  • Includes a servlet and a servlet filter for simple generation of PDF's from XML or JSP pages.
  • Auto pagination of content with page headers and footers
  • Familiar HTML syntax - <a>, <ul>, <p>, <table>, <td> and so on - simpler and faster than FOP
  • Unicode support, Encryption, TrueType fonts, Barcodes and more
  • Load existing PDF documents as templates
  • Digitally sign documents
  • Create and edit interactive Forms, or "AcroForms"
The following is an example of how to use the Report generation library to create PDF files using an XML for input Data, and an XSL as a template. Follow these steps to implement the example
  1. Download Big Faceless Report generator from here. You only have to include the bforeport.jar file in your classpath.
  2. Create the input XML file as shown below:
    <?xml version="1.0" encoding="UTF-8"?>
    <Org>
    <Employee>
    <firstName>Asif</firstName>
    <lastName>Mandvi</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>James</firstName>
    <lastName>Baker</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Jon</firstName>
    <lastName>Stewart</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Stephen</firstName>
    <lastName>Colbert</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Samantha</firstName>
    <lastName>Bee</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Jon</firstName>
    <lastName>Oliver</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    </Org>
    test.xml
  3. Create the template for the PDF(XSL) as shown below.
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" />
    <xsl:preserve-space elements="true" />
    <xsl:template match="Org">
    <pdf>
    <body>
    <table font-size="12pt" width="700px">
    <tr font-weight="bold">
    <td>First Name</td>
    <td>Last Name</td>
    <td>Date of Birth</td>
    </tr>
    <xsl:for-each select="/Org/Employee">
    <tr>
    <td>
    <xsl:value-of select="firstName" />
    </td>
    <td>
    <xsl:value-of select="lastName" />
    </td>
    <td>
    <xsl:value-of select="dateOfBirth" />
    </td>
    </tr>
    </xsl:for-each>
    </table>
    </body>
    </pdf>
    </xsl:template>
    </xsl:stylesheet>
    test.xsl
    This XSL file will be used to create the final XML file that will sent as input to the Report generator.
  4. Transform the XML to the format required by the report generator: The XML file cannot be used as input to the report generator directly. It has to be first transformed into the required format. That is reason for using the XSL.
    public class ConvertXML {
    public void renderReport() {
    try {
    TransformerFactory factory = TransformerFactory.newInstance();
    StreamSource stylesheet = new StreamSource(new FileInputStream("c:\\pdf\\test.xsl"));
    Transformer transformer = factory.newTransformer(stylesheet);
    Source src = new StreamSource(new FileInputStream("c:\\pdf\\test.xml"));
    Result res = new StreamResult(new FileOutputStream("c:\\pdf\\intermediate.xml"));
    transformer.transform(src, res);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    ConvertXML.java
  5. The following code can be used to generate the final PDF: The PDFGenerator first uses the ConvertXML to transform the input to the report generator input format (intermediate.xml), and then invokes the report generator.
    public class PDFGenerator {
    public void createPDF(String xmlfile, OutputStream out) {
    ReportParser parser;
    try {
    parser = ReportParser.getInstance();
    InputSource src = new InputSource(new FileInputStream(xmlfile));
    PDF pdf = (PDF) parser.parse(src);
    pdf.render(out);
    out.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    public static void main(String args[]) {
    PDFGenerator gen = new PDFGenerator();
    OutputStream os = null;
    try {
    ConvertXML cx = new ConvertXML();
    cx.renderReport();
    os = new FileOutputStream("c:\\pdf\\test.pdf");
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    gen.createPDF("C:\\pdf\\intermediate.xml", os);
    }
    }
    PDFGenerator.java

Monday, December 04, 2006

Using Quartz Scheduler in a cluster

In a previous post, I described how to use Quartz scheduler for scheduling. In this post, I describe the configuration changes required for using Quartz Scheduler with Scheduling. 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.
The following is an example of how to setup clustering. I implemented it as a stand-alone application. The same settings can be used in clusetered environment.
  1. Copy the source code from the example from the quartz example and add the follwing line to the QuartzTest.java class
    jobDetail.setRequestsRecovery(true);
    before adding jobDetail to the trigger. This is job failover.
  2. You have to add the following to the quartz.properties file:
    org.quartz.jobStore.isClustered = true
    org.quartz.jobStore.clusterCheckinInterval = 20000
    This sets up quartz for clustering
  3. Each server must have the same copy of the configuration file.
    org.quartz.scheduler.instanceId = AUTO
    To auto-generate instance ids.
  4. Create the data tables by using the sql scripts provided with the quartz download. The scripts are in the quartz\docs\dbTables directory.
When running the example, you can see the changes in DB in the SIMPLE_TRIGGERS and FIRED_TRIGGERS tables. The following is the quartz.properties file that I used. It has to be in the classpath.
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_

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

#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@localhost:1521:orcl
org.quartz.dataSource.myDS.user = scott
org.quartz.dataSource.myDS.password = tiger
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
In order to use the datasources from your application server, change the datasource definition to the following
org.quartz.dataSource.myDS.jndiURL=jdbc/myDataSource
org.quartz.dataSource.myDS.java.naming.factory.initial=com.evermind.server.rmi.RMIInitialContextFactory
org.quartz.dataSource.myDS.java.naming.provider.url=ormi://localhost
org.quartz.dataSource.myDS.java.naming.security.principal=admin
org.quartz.dataSource.myDS.java.naming.security.credentials=123

Monday, November 27, 2006

Scheduling with Quartz

Batch solutions are ideal for processing that is time and/or state based:
  • Time-based: The business function executes on a recurring basis, running at pre-determined schedules.
  • State-based: The jobs will be run when the system reaches a specific state.
Batch processes are usually data-centric and are required to handle large volumes of data off-line without affecting your on-line systems. This nature of batch processing requires proper scheduling of jobs. Quartz is a full-featured, open source job scheduling system that can be integrated with, or used along side virtually any Java Enterprise of stand-alone application. The Quartz Scheduler includes many enterprise-class features, such as JTA transactions and clustering. The following is a list of features available:
Skip to Sample Code
  • Can run embedded within another free standing application
  • Can be instantiated within an application server (or servlet container).
  • Can participate in XA transactions, via the use of JobStoreCMT.
  • Can run as a stand-alone program (within its own Java Virtual Machine), to be used via RMI
  • Can be instantiated as a cluster of stand-alone programs (with load-balance and fail-over capabilities)
  • Supoprt for Fail-over
  • Support for Load balancing.
The following example demonstrates the use of Quartz scheduler from a stand-alone application. Follow these steps to setup the example, in Eclipse.
  1. Download the latest version of quartz from opensymphony.
  2. Make sure you have the following in your class path (project-properties->java build path):
    • The quartz jar file (quartz-1.6.0.jar).
    • Commons logging (commons-logging-1.0.4.jar)
    • Commons Collections (commons-collections-3.1.jar)
    • Add any server runtime to your classpath in eclipse. This is for including the Java transaction API used by Quartz. Alternatively, you can include the JTA class files in your classpath as follows
      1. Download the JTA classes zip file from the JTA download page.
      2. Extract the files in the zip file to a subdirectory of your project in Eclipse.
      3. Add the directory to your Java Build Path in the project->preferences, as a class directory.
  3. Implement a Quartz Job: A quartz job is the task that will run at the scheduled time.
    public class SimpleJob implements Job {
    public void execute(JobExecutionContext ctx) throws JobExecutionException {
    System.out.println("Executing at: " + Calendar.getInstance().getTime() + " triggered by: " + ctx.getTrigger().getName());
    }
    }
    SimpleJob.java
  4. The following piece of code can be used to run the job using a scheduler.
    public class QuartzTest {
    public static void main(String[] args) {
    try {
    // Get a scheduler instance.
    SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    Scheduler scheduler = schedulerFactory.getScheduler();

    long ctime = System.currentTimeMillis();

    // Create a trigger.
    JobDetail jobDetail = new JobDetail("Job Detail", "jGroup", SimpleJob.class);
    SimpleTrigger simpleTrigger = new SimpleTrigger("My Trigger", "tGroup");
    simpleTrigger.setStartTime(new Date(ctime));

    // Set the time interval and number of repeats.
    simpleTrigger.setRepeatInterval(100);
    simpleTrigger.setRepeatCount(10);

    // Add trigger and job to Scheduler.
    scheduler.scheduleJob(jobDetail, simpleTrigger);

    // Start the job.
    scheduler.start();
    } catch (SchedulerException ex) {
    ex.printStackTrace();
    }
    }
    }
    QuartzTest.java

    A trigger is used to define the schedule in which to run the job.
For more information on batch processing visit: "High volume transaction processing in J2EE"

Popular Posts