Wednesday, May 9, 2012

PDF file download dialog with JAX-RS

Below I will show how to display PDF file download dialog to the user using REST JAX-RS.

My implementation below will NOT create PDF file in user's directory until the user choose "save as" in the dialog box. To achieve this, I used ByteArrayInputStream class.

 

ByteArrayOutputStream baos = new ByteArrayOutputStream();

//This is just PDF generation API
JasperExportManager.exportReportToPdfStream(jasperPrint, baos);
                
byte[] entity = baos.toByteArray();
                
return Response.ok(entity)
        .header("Content-Disposition", "attachment; filename=MyAwesomeJasperReportDownload.pdf")
        .type("application/pdf")
        .build();

Jasper Report - how to write Java code without query

I've seen many article talking about how to write Java code to generate Jasper Report using SQL query.

But in some occasion you don't want to write SQL exposing table names etc other than your application code.

In my project I get data from database and the data is processed (modified) to output in PDF.

Below is example of not using database connection.


 

//------- import ---------
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.view.JasperViewer;


//------emitted some code ----------

public static void main(String[] args) {
        
       
        try {
            
            File jrxmlFile = new File("C:\\Users\\m-tak\\report2.jrxml");

            if(jrxmlFile.exists()) {

                //jrxml compile
                JasperReport jasperReport = JasperCompileManager.compileReport(jrxmlFile.getAbsolutePath());
                
                
                //detail section
                List<Map<String, ?> list = new ArrayList<Map<String, ?>();
                
                Random rd = new Random();
                for(int j = 0; j < 10; j++) {
                    Map<String, Object> map2 = new HashMap<String, Object>();
                    map2.put("listItem", rd.nextInt());
                    map2.put("listItem2", new StringBuilder().append(rd.nextInt()).append("foobar"));
                    list.add(map2);
                }
                
                JRMapCollectionDataSource dataSource = new JRMapCollectionDataSource(list);
                
                
                Map params = new HashMap();
                params.put("orderNumber", "12345");
                params.put("payment", "6789");
                params.put("other", "something");
                

                JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource);
                JasperViewer.viewReport(jasperPrint, false);
                
            }
        }
        catch(Exception e) {
            System.out.println("-------------------- PDF exception ");
            System.out.println(e);
        }
        System.out.println("DONE");
        
}


First of all let me explain what data we need to prepare.

  • 1. Map of data used as parameter. i.e "params"
  • 2. List which contains Map used as field. i.e "dataSource"
  • Note: Map used in 1 and 2 are of different Map so don't confuse them.



     
     
    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource);
     
    
    


    The code below prepares the params. It's just simple Map with ordinary key/value pair.

    
    Map params = new HashMap();
    params.put("orderNumber", "12345");
    params.put("payment", "6789");
    params.put("other", "something");
    
    


    Next we need List contains Map for dataSource. At the end, the List is passed to JRMapCollectionDataSource.

    List<Map<String, ?> list = new ArrayList<Map<String, ?>();
                    
    Random rd = new Random();
    for(int j = 0; j < 10; j++) {
        Map<String, Object=""> map2 = new HashMap<String, Object>();
        map2.put("listItem", rd.nextInt());
        map2.put("listItem2", new StringBuilder().append(rd.nextInt()).append("foobar"));
        list.add(map2);
    }
                    
    JRMapCollectionDataSource dataSource = new JRMapCollectionDataSource(list);
    


    Finally it's time to pass params and fields (dataSource) to JasperFillManager and JasperViewer will display the PDF view.

    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource);
    JasperViewer.viewReport(jasperPrint, false);
    

    Tuesday, January 24, 2012

    How to use Open2Test keyword with QTP

    Open2Test is add-on style keyword-driven framework which aims to replace test script with excel defined set of keywords.

    http://www.open2test.org/

    Today, I will explain how to define the keyword. The reason I'm posting such information is because Open2Test documentation is the worst documentation I've ever read. I know it's open source but lacking responsibility to guide users to the point that they can actually "use" it.

    NOTE: Open2Test does not provide the forum to discuss about the framework but instead they have support email which you don't get response at all. (I sent 2 emails regarding to keyword definition etc and it has been a week since)

    Since I used QTP to do my research, I will show how the keyword should look like.

    I assume you have basic knowledge of how QTP works.

    Object Repository

    What makes QTP powerful tool is that it has Object Repository where you can store test object and all the test uses the repository. In the test script, you use test object name in the repository to refer to actually object such as DOM Element or Windows Object. Open2Test uses the test object name in the Object Repository.

    For instance, in the QTP Object Repository, there is test objects of a website.

    Browser --> myBrowser
                     |
                     |---Page --> myPage
                            |
                            |---Frame --> view
                                          |
                                          |----->WebEdit --> FirstName (this is textbox)
    

    Now Open2Test keyword should look like below in order to type into the textbox.

    r wait 2
    r context browser;myBrowser page;myPage::frame;view
    r perform textbox;FirstName set:hello world

    The first row - wait for 2 second

    The second row - move focus to frame inside of page inside of browser

    The third row - type "hello world" into the textbox.

    I had to read source code of Open2Test QTP web to find out this. The documentation does not tell me how I should define context keyword. Anyway, I confirmed that above works just fine. If anyone has an issue please let me know I may be able to help

    Thursday, January 12, 2012

    Call to jQuery dialog will execute external Javascript!

    I came across this while debugging jsp page. Totally took my few hours of scratching my head til bleed.

    The gotcha is when included jsp imports javascript and if the jsp is within jQuery dialog, the imported javascript is also read by browser once.

    Maybe easier to show the code

    foo1.jsp

    
    
        
    
            /* NOTE: jQuery dialog import is omitted for simplicity */
    
            
        
    
        
            

    Hello World!


    foo2.jsp

    
        
             
        
        
        
    
    

    alert.js

    alert("alert");
    

    What happen here is when the button is clicked, dialog is displayed but before that, alert message from alert.js is executed!

    This proves that dialog section includes javascript, it will get executed

    Tuesday, December 20, 2011

    HTML5 Custom Form Validation with Ajax

    It is fairly easy to create HTML5 form validation with non-ajax. But I found out that form validation with ajax is bit tricky. If anyone knows better way please let me know.

    The problem was when to call setCustomValidity(). I had to call it inside of onclick event handler which runs just before form submission.

    So, when you click on submit button, onclick is fired and initValidation() is called. The method checks whether input is equals to the string "tt". If so it will set custom error message (i.e. setCustomValidity() )

    You have to make sure to kill the submit by event.preventDefault()

    NOTE: I tried this without using onclick. I put form validation code inside of submit() but setCustomValidation() is called too late there thus error popup didn't show up. (if you click submit one more time, it will show the popup.)

    CODE:

    
    
    Test1: Test2:
    
    
    $(document).ready(function() {
        $("#myForm").submit(function(event) {
            event.preventDefault(); //cancel submit
            
            //your ajax code here...
        })
    });
    
    function initValidation() {
        var mtxt = document.getElementById("myText");
        mtxt.setCustomValidity(""); //reset
        
        if($("#myText").val() == "tt") {
            mtxt.setCustomValidity("this is my custom error message");
        }
    }
    
    
    

    Monday, December 19, 2011

    Strategy design pattern (Masatosan version)

    I've seen countless Strategy pattern described on the web and none of them really get me so far. They use Dog, Cat, Coffee, even worse, JComponent.. sure I can "programming to interface not implementation."

    Still not getting it without writing my own strategy pattern with my own words. (Doesn't matter what terms I use, the point is I get the concept!)

    Here is my version of strategy design pattern:

        
    
    public interface Console {
        public void launchGame();
    }
    
    public class XBox360 implements Console {
        public void launchGame() {
            System.out.print("I see the ring of death!");
        } 
    }
    
    public class PlayStation3 implements Console {
        public void launchGame() {
            System.out.println("SONY is being hacked by a kid");
        }
    }
    
    public class Wii implements Console {
        public void launchGame() {
            System.out.println("I think my Wii controller is in my neighbor's backyard");
        }
    }
    
    public class Me {
        private Console console = null;
    
        public Me(Cosole console) {
            this.console = console;   
        }
    
        public setConsole(Console console) {
            this.console = console;
        }
    
        public void turnOn() {
            if(console != null) {
                console.launchGame();
            }
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Me me = new Me(new XBox360());
            me.turnOn(); //"I see the ring of death!"
            me.setConsole(new PlayStation3());
            me.turnOn(); //"SONY is being hacked by a kid"
            me.setConsole(new Me(new Wii());
            me.turnOn(); //I think my Wii controller is in my neighbor's backyard")
        }
    }
    
        

    Sunday, December 18, 2011

    Custom form validation with HTML5!

    I know there are many HTML5 form validation on the web but I made my own test demo so let me share.

    The important thing is I wanted to create my own custom validation rule and custom error message.

    I have 2 input text fields. Left field value has to be smaller than right field value. (like to-from date if u will)
    Then my javascript compare each value and triggers custom validation error.

    Note that you must remember to put empty string in setCustomValidity() otherwise after error is thrown, second time input will still cause custom error message to be shown.

    For more detail about custom validation, check out: http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#dom-cva-setcustomvalidity



    Custom: less: <= more:

    Code:


    
    

      
    Custom: less: <= more: