Powered By Blogger

Thursday, August 25, 2011

Printing with JEditorPane

The following is an illustration of printing with Java. Here I have used JEditorPane and PrinterJob. What printed in this example is an html page.

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


package ds.demo.service;

import java.awt.print.PrinterJob;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;

import javax.swing.JEditorPane;

public class Test {

    static MessageFormat head = new MessageFormat("");
    static MessageFormat foot = new MessageFormat("");

    public static void main(String[] args) throws Exception {

        PrinterJob pj = PrinterJob.getPrinterJob();
        if(pj.printDialog()) {
            JEditorPane text = new JEditorPane("text/html", "text");
//            text.setText("Return this page to Shyarmal.");
            text.read(new BufferedReader(new InputStreamReader(new FileInputStream(new File("a.html")))), "");
            text.repaint();
            pj.setPrintable(text.getPrintable(head, foot));
            pj.print();
            System.out.println("done .............. ");
        }
    }
}

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

First a PrinterJob instance is obtained.
          PrinterJob pj = PrinterJob.getPrinterJob();

Then a panel will be popped to take a user input.  It's done by the code segment, 'pj.printDialog()', which returns true if the user chooses to print and false otherwise.


Then a JEditorPane instance is formed specifying the content type and an initial text.
         JEditorPane text = new JEditorPane("text/html", "text");
An alternative way to do the same is;
        JEditorPane text = new JEditorPane();
        text.setContentType("text/html");

The content should be set to the JEditorPane for printing.
Text can either be set like
       'text.setText("Return this page to Shyarmal.");'
or read from a file as done in the example
[ text.read(new BufferedReader(new InputStreamReader(new FileInputStream(new File("a.html")))), ""); ]

Then repaint method should be called on the JEditorPane for the changes to it be updated.

'pj.setPrintable(text.getPrintable(head, foot))' sets the JEditorPane for printing.
The print() method of PrinterJob, does the printing.


thanks,
Shyarmal.

Run Java main method from a shell script

Following is a shell script, which runs a Java class 'Example' accepting one argument. Further it puts the required libraries and configuration files to the class path.

#!/bin/bash
_CP=../conf/

for i in ../lib/* ; do
    if [ "$_CP" != "" ]; then
          _CP=${_CP}:$i
    else
         _CP=$i
    fi

done

for i in ../conf/*.* ; do
    if [ "$_CP" != "" ]; then
          _CP=${_CP}:$i
    else
         _CP=$i
    fi

done

    echo "running ...... "

    echo "--------------------------------------------------------"
    java -Xms64m -Xmx254m -cp $_CP:. com.shyarmal.Example $1


thanks,
Shyarmal.

Thursday, August 4, 2011

Printing example with Java EE

Following  is an approach to printing a document using a servlet. The example uses a template which is in html to generate a page (an invoice) and then prints it. Place holders of variable fields of the invoice are obtained via the user session and replaced appropriately. Since the clients should be getting a printout of the invoice, the printing has to be done through the browser (using a javascript).

===================================================================
package com.shyarmal.web.services;

import com.shyarmal.web.util.DateTimeUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

public class InvoicePrinter extends HttpServlet {

    private static final String TEMPLATE_NAME = "/invoice.tpl";
    
    private static final Logger LOGGER = Logger.getLogger(InvoicePrinter.class);
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        LOGGER.info("printing receipt ....");
        try {
            Map receiptDetails = (Map) req.getSession().getAttribute("recieptParameters");
            receiptDetails.put("date", DateTimeUtil.getDate());
            receiptDetails.put("time", DateTimeUtil.getTime());
            PrintWriter pw = resp.getWriter();
            pw.print(replaceTokens(readTemplate(), receiptDetails));
            pw.flush();
            pw.close();
        } catch (Exception e) {
            LOGGER.error("Printing failed .... ", e);
        } finally {
            LOGGER.info("quit printer task.... ");
        }
    }
    
    private String readTemplate() throws IOException {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(TEMPLATE_NAME)));
            StringBuffer sb = new StringBuffer();
            while(br.ready()) {
                sb.append(br.readLine());
            }
            
            return sb.toString();
        } finally {
            br.close();
        }
    }
    
    private String replaceTokens(String text, Map replacements) {
        Pattern pattern = Pattern.compile("\\[(.+?)\\]");
        Matcher matcher = pattern.matcher(text);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()) {
            String replacement = (String)replacements.get(matcher.group(1));
            if(replacement != null) {
                matcher.appendReplacement(sb, "");
                sb.append(replacement);
            }
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

}
===================================================================

I have posted a sample template which will be used to generate the invoice below. The segments to be replaced are enclosed with square brackets. Replacement of tokens is done in the method replaceTokens(String, Map) method. The keys of the map should map the names of the placeholders which are given within square brackets. Actually the printing is done by onLoad='self.print()' call in the body tag of the template. All what the servlet does is creating the specific invoice for the user and displaying it.

===================================================================
<!DOCTYPE html PUBLIC
'-//W3C//DTD XHTML 1.0 Transitional//EN'
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www.w3.org/1999/xhtml'> <head> <title>Untitled Document</title> <style type='text/css'> <!-- ----- css codes ------- --> </style> </head> <body style='font: Arial; color:#333333' onLoad='self.print()'> <br /><br /><br /> <table width='100' border='0' align='center' cellpadding='1' cellspacing='0' bgcolor='#A21D18'> <tr> <td bgcolor='#A21D18'>
<table width='455' border='0' align='left' cellpadding='0' cellspacing='0' bgcolor='#FFFFFF'> <tr> <td width='350' height='30' class='style2'> <div align='left' style='padding-left:30px;'>Date : [date] </div> </td> <td width='350' class='style2'> <div align='left' style='padding-left:30px;'>Time : [time] </div> </td> </tr> <tr> <td colspan='2' class='style2'>
<div align='left' style='padding-left:50px; padding-right:50px; padding-top:5px;'> <table width='100%' border='0' cellspacing='0' cellpadding='0'> <tr> <td width='48%'><u>Invoice</u></td> <td width='4%'>&nbsp;</td> <td width='48%'>&nbsp;</td> </tr> <tr> <td>ID/Passport No </td> <td align='center'>:</td> <td>[nic]</td> </tr> <tr> <td>Name</td> <td align='center'>:</td> <td>[first_name] &nbsp; [last_name]</td> </tr> <tr> <td>Billing Address</td> <td align='center'>:</td> <td>[address]</td> </tr> <tr> <td>Billing Country</td> <td align='center'>:</td> <td>Sri Lanka</td> </tr> <tr> <td>Amount </td> <td align='center'>:</td> <td>LKR [amount]</td> </tr> </table> </div></td> </tr> </table></td> </tr> </table> </body> </html>
===================================================================

The javascript code in the jsp will be opening a new window and loading the invoice for the particular customer. The dimensions of the window opened will be 800 x 600 and will be sending a request to the above servlet with the url 'shopping/pringInvoice'. ['shopping/pringInvoice' is mapped to the servlet in the web.xml file.]
===================================================================

<script type="text/javascript">
  function print() {
    window.open('/shopping/printInvoice','receipt','width=600,height=800');
  }
</script>
===================================================================

The servlet should be defined and mapped in the web.xml.
===================================================================
<servlet-mapping>
<servlet-name>printInvoice</servlet-name>
<url-pattern>/printInvoice</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>printInvoice</servlet-name>
<servlet-class>com.shyarmal.web.services.InvoicePrinter</servlet-class>
</servlet>
==================================================================

thanks,
Shyarmal.

Sunday, July 31, 2011

Embed youtube video in HTML

 The following code will embed a you tube video to your html page. The attributes, value and src of param with name movie and embed tags respectively holds the url to the video, which is being embedded. The last segment of the url is the video ID (which is used to identify a video). The ID in the following example is rxUm-2x-2dM. 

<object width="425" height="350">
             <param name="movie" value="http://www.youtube.com/v/rxUm-2x-2dM"/>
             <param name="wmode" value="transparent" />
             <param name="allowFullScreen" value="true" />
             <embed src="http://www.youtube.com/v/rxUm-2x-2dM"
                      type="application/x-shockwave-flash"
                      wmode="transparent" width="425" height="350"
                      allowFullScreen="true">
              </embed>
</object>

Furthermore video options such as height, width, mode, full screen can be specified, as shown in the example.  Details about video options can be found at http://code.google.com/apis/youtube/player_parameters.html.

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.

Saturday, July 23, 2011

TestNg DataProvider Example

Data providers are used to feed data to a test method, often when a method is to be tested against different scenarios (or data sets), which are expected to give the same result.
This is an illustration of a data provider.

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

@Test(dataProvider = "incorrect-data",
                   expectedExceptions = {InvalidInputException.class}, enabled = true)
public void testCreateWithIncorrectData(Byte bt, byte[] data) {
          timeStamp.create(bt.byteValue(), data);
}

@DataProvider(name = "incorrect-data")
public Object[][] incorrectData() {
          return new Object[][]{
                {new Byte((byte)1), new byte[]{(byte)0xF3, 0, -127, 100, 120, 0, 0}},
                {new Byte((byte)1), new byte[]{(byte)0xF1, 0, -127, 5, 0, 0, 0}},
                {new Byte((byte)3), new byte[]{(byte)0xF1, 0, -127, 5, 0, 0, 0}},
                {new Byte((byte)3) ,new byte[]{(byte)0xF3, 0, 60, 100, 120, 0, 0}}
        };
}

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

The example above tests a creation of time stamps for incorrect data. The data provider (annotated with @DataProvider) provides data to the test method (annotated with @Test).

Annotations;

  • @Test: Methods annotated with this will be considered as a test method. The attribute dataProvider configures the data provider to the test case, expectedExceptions is to specify the exceptions expected to be thrown and enable is used to make the test method enabled or disabled.
  • @DataProvider: Methods annotated with this are data providers. A data provider should have a name which is given as the 'name' attribute in order to be used by a test method.

The method incorrectData() returns a two-dimensional object array of size, 4. Each of the four arrays has two elements, which are arguments to the test method (testCreateWithIncorrectData(Byte, byte[])). Data types of the elements of each secondary array should exactly match the parameters of the test method. Since there are four sets of data, the test method will be executed four times, in one run of the test case. All four runs of the method should throw InvalidInputException exception if the test case is to pass.

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.