Saturday, April 30, 2011

Design Patterns(Singleton, Decorator, Immutable Class)

Hey...

In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Here I will introduce 3 design patterns. More design patterns are available in my future posts.

1. Singleton
1.1 Pattern Goal
This Pattern make an object to be created once in whole application life cycle. If you want any thread or request uses and shares only one instance of indicated object you can apply this pattern. This pattern deals with concurrency problem of critical sections in class methods. Thus, take care of concurrency whenever you use this pattern as a solution.
1.2 Pattern Detail
To make a class have single object in application scope, we should make the constructor of the class, private. This prevents of creating the class.
public class TestClass{
    private TestClass() {
    }
}
Then we make a private static instance of the class and initiate it in an static method. In this method we should check if the static field has been initiated or not. If yes we shouldn't do that.
    public class TestClass {
        private static TestClass testClass;

        private TestClass() {
        }

        public static TestClass getInstance() {
            if (testClass == null) {
                testClass = new TestClass();
            }
            return testClass;
        }
    }
That's it. The pattern is complete. To use this class, you must not new it. you can use getInstance method.
...
TestClass testClass = TestClass.getInstance();
testClass.customMethod();
...
1.3 Pattern Sample
We want to know how many times a button is clicked. Here is the class to save click count.




I create a class called ClickButton then apply singleton pattern to it. Any time button is clicked we should run click method of this class. Here is the code:
public class ClickButton {
    private static ClickButton clickButton;
    Integer clickCount;

    private ClickButton() {
        clickCount = 0;
    }

    public static ClickButton getInstance() {
        if (clickButton == null) {
            clickButton = new ClickButton();
        }
        return clickButton;
    }

    public void click() {
        synchronized (clickCount) {
            clickButton.clickCount++;
        }
    }

    public Integer getClickCount() {
        return clickButton.clickCount;
    }
}
and here is the use of this class:
@Controller
@Scope("prototype")
@RequestMapping("/button")
public class ButtonController {

...
    @RequestMapping("/click")
    public String click(@ModelAttribute("button")ClickButton clickButton, HttpServletRequest request) {
        clickButton.click();
        request.setAttribute("clickcoutn", clickButton.getClickCount());
        return "button.view";
    }
...
}
and here is the result:

2. Decorator
1.1 Pattern Goal
Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality. On the other hands we can decorate a class dynamically. For example a simple coffee class has only coffee as ingredients. But we will be able to add milk, sugar, ... to it dynamically when apply this patter.

1.2 Pattern Detail
We should make an interface and a simple form of class implementing the interface. Another class is decorated class implementing the interface. The decorator class should contains a protected object of the interface and initiate it in its constructor. In implementation of the interface methods, We should just call and return the related method of the protected field. The decorator class should be an abstract class to prevent directed usage.
Now you can create other classes extending decorator class. Then override the interface methods of the decorator class in your custom class and do any decoration to the methods. Here is the pattern structure:

1.Interface:
public interface TestClass{
    Object testMethod();
}
2.Simple Form:
public class SimpleTestClass implements TestClass{
    public Object
testMethod() {
        return Do something;
    }

3.Decorator Class:
public abstract class DecoratorTestClass implements TestClass{
    protected
TestClass testClass;

    public
DecoratorTestClass(TestClass testClass) {
        this.
testClass = testClass;
    }

    public
Object testMethod() {
        return
testClass.testMethod();
    }
}
4.Custom Class:
public class CustomTestClass1 extends DecoratorTestClass{
    public
CustomTestClass1(TestClass testClass) {
        super(
testClass);
    }

    @Override
    public Object
testMethod() {
        Object test = super.
testMethod();
        do something with test
        return
test;
    }
}


public class CustomTestClass2 extends DecoratorTestClass{
    public CustomTestClass2(TestClass testClass) {
        super(testClass);
    }

    @Override
    public Object testMethod() {
        Object test = super.testMethod();
        do something with test
        return test;
    }
}

...
public class CustomTestClassN extends DecoratorTestClass{
    public CustomTestClassN(TestClass testClass) {
        super(testClass);
    }

    @Override
    public Object testMethod() {
        Object test = super.testMethod();
        do something with test
        return test;
    }
}
5. Use of Decorator Class:
public class TestController {
public Object TestMethod(){
        TestClass test = new CustomTestClass2(new CustomTestClass5(new CustomTestClass7(new SimpleTestClass())));
        return test.testMethod();
    }
}

1.3 Pattern Sample
House List example is a sample that works with house class. House class has two methods including getFacilityLIST() and getPrice(). I'm going to apply decorator pattern to these two methods. Some facilities will be apply to the basic house and its price gets more dynamically. Here is the class diagram:
and here is the source code:
1. Interface:
public interface House {
    List<String> getFacilityLIST();
    Long getPrice();
}
2. Simple Class:
public class SimpleHouse implements House{
    public List<String> getFacilityLIST() {
        List<String> facilityList = new ArrayList();
        facilityList.add("Building");
        facilityList.add("Restroom");
        facilityList.add("Kitchen");
        facilityList.add("Salon");
        return facilityList;
    }

    public Long getPrice() {
        return 1000l;
    }
}
2. Decorator Class:
public abstract class DecoratorHouse implements House{
    protected House decoratedHouse;

    public DecoratorHouse(House decoratedHouse) {
        this.decoratedHouse = decoratedHouse;
    }

    public List<String> getFacilityLIST() {
        return decoratedHouse.getFacilityLIST();
    }

    public Long getPrice() {
        return decoratedHouse.getPrice();
    }
}
3. Custom Classes:
public class SingleRoomHouse extends DecoratorHouse{
    public SingleRoomHouse(House decoratedHouse) {
        super(decoratedHouse);
    }

    @Override
    public List<String> getFacilityLIST() {
        List<String> facilityList = super.getFacilityLIST();
        facilityList.add("1 Room");
        return facilityList;
    }

    @Override
    public Long getPrice() {
        return super.getPrice() + 200l;
    }
}


public class DoubleRoomHouse extends DecoratorHouse{
    public DoubleRoomHouse(House decoratedHouse) {
        super(decoratedHouse);
    }

    @Override
    public List<String> getFacilityLIST() {
        List<String> facilityList = super.getFacilityLIST();
        facilityList.add("2 Rooms");
        return facilityList;
    }

    @Override
    public Long getPrice() {
        return super.getPrice() + 400l;
    }
}


public class CompleteHouse extends DecoratorHouse{
    public CompleteHouse(House decoratedHouse) {
        super(decoratedHouse);
    }

    @Override
    public List<String> getFacilityLIST() {
        List<String> facilityList = super.getFacilityLIST();
        facilityList.add("Gardened Yard");
        facilityList.add("Car Parking");
        return facilityList;
    }

    @Override
    public Long getPrice() {
        return super.getPrice() + 1000l;
    }
}


public class ModernHouse extends DecoratorHouse{
    public ModernHouse(House decoratedHouse) {
        super(decoratedHouse);
    }

    @Override
    public List<String> getFacilityLIST() {
        List<String> facilityList = super.getFacilityLIST();
        facilityList.add("Closet");
        facilityList.add("Pool");
        return facilityList;
    }

    @Override
    public Long getPrice() {
        return super.getPrice() + 1000l;
    }
}

3. Immutable Object
1.1 Pattern Goal
To make an object read only or even make an object read only in some places of you application, you can apply this pattern to you classes.

1.2 Pattern Detail
First of all you should make a wrapper to your class. We call this wrapper class, Immutable Class. The Immutable Class should have a private final field with the indicated class data type and initiate it in the constructor. Then make a getter for that. In the getter method you should return a clone of the field. This make a new instance of the object and this make the object read only. Whenever you get the object from this method a new instance will be make so the object which is passed from the constructor will stay safe and won't be changed.
Note: Your Object should be cloneable
Take a look to these codes:
Base class:
public class TestClass implements Cloneable{
    String field1;

    public
TestClass(String field1) {
        this.
field1= field1;
    }

    public String get
Field1() {
        return name;
    }

    public void setF
ield1(String field1) {
        this.
field1= field1;
    }

    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
Immutable class:
public class ImmutableTestClass {
    private final
TestClass testClass;

    public
ImmutableTestClass(Student testClass) {
        this.
testClass= testClass;
    }

    public
testClass getTestClass() throws CloneNotSupportedException {
        return (
TestClass) testClass.clone();
    }
}

1.3 Pattern Sample
Student class is an entity bean class. I will make it Immutable and show you if you change the object, even manually, the major object will be never changed. Here is the class diagram:

 

And here is the source code:
Entity Bean:
public class Student implements Cloneable{
    String name;
    String stNo;
    Float gpa;

    public Student(String name, String stNo, Float gpa) {
        this.name = name;
        this.stNo = stNo;
        this.gpa = gpa;
    }

    public String getName() {
        return name;
    }

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

    public String getStNo() {
        return stNo;
    }

    public void setStNo(String stNo) {
        this.stNo = stNo;
    }

    public Float getGpa() {
        return gpa;
    }

    public void setGpa(Float gpa) {
        this.gpa = gpa;
    }

    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
Immutable Class:
public class ImmutableStudent {
    private final Student student;

    public ImmutableStudent(Student student) {
        this.student = student;
    }

    public Student getStudent() throws CloneNotSupportedException {
        return (Student) student.clone();
    }
}
Use of Immutable Class:
@Controller
@Scope("prototype")
@RequestMapping("/student")
public class StudentController {
    @ModelAttribute("student")
    public ImmutableStudent studentModel() {
        return new ImmutableStudent(new Student("Mostafa Rastgar", "2020041251", 15.2f));
    }

    @RequestMapping("/view")
    public String view() {
        return "student.view";
    }

    @RequestMapping("/save")
    public String save(@ModelAttribute("student") ImmutableStudent immutableStudent, @RequestParam(value="student.name", required = true) String name, @RequestParam(value="student.stNo", required = true) String stNo, @RequestParam(value="student.gpa", required = true) Float gpa, HttpServletRequest request) throws CloneNotSupportedException {
        Student student = immutableStudent.getStudent();
        student.setName(name);
        student.setStNo(stNo);
        student.setGpa(gpa);
        request.setAttribute("studentParam", student);
        return "student.view";
    }
}
As you see, although the value of entity fields will be set manually(red lines), but the student shown in the form will stay in its init value(the value which is set in studentModel method) and never change. Because we use immutableStudent.getStudent() in save method and it makes a new instance from the object which is passed into its constructor.

Source Code
You can download those 3 samples from here. After the deployment the start page is: http://localhost:8080/button/view.html



all rights reserved by Mostafa Rastgar and Programmer Assistant weblog

Monday, April 25, 2011

Spring + JasperReports

Hey...

Reports are one of the major parts of an enterprise application. There are some open source reporting tools for java applications like JasperReports, JFreeReport, JXLS, and Eclipse BIRT.  Here I'm going to describe one of the powerful reporting tools called JasperReports which can be embedded in your java application.


JasperReports
JasperReports is an open source Java reporting tool that can write to screen, to a printer or into PDF, HTML, Microsoft Excel, RTF, ODT, Comma-separated values and XML files.

It can be used in Java-enabled applications, including Java EE or Web applications, to generate dynamic content. It reads its instructions from an XML or .jasper file.

JasperReports is part of the Lisog open source stack initiative.

Features
JasperReports is an open source reporting library that can be embedded into any Java application. Features include:
  • Scriptlets may accompany the report definition, which the report definition can invoke at any point to perform additional processing. The scriptlet is built using Java, and has many hooks that can be invoked before or after stages of the report generation, such as Report, Page, Column or Group.
  • Sub-reports
For users with more sophisticated report management requirements, reports designed for JasperReports can be easily imported into the JasperServer - the interactive report server.

JRXML
JasperReports reports are defined in an XML file format, called JRXML, which can be hand-coded, generated, or designed using a tool. The file format is defined by a Document Type Definition (DTD), providing limited interoperability.

The main difference between using XML and a .jasper file is that the XML file should be compiled at runtime using the JasperCompileManager class.

Third party tools
There are many tools providing JasperReport capabilities:
  • iReport, an open source standalone graphical program that provides report designer capabilities, and is able to run reports using all data source supported by the JasperReports engine. iReport is actively maintained by JasperSoft.
  • DynamicReports, an open source Java API reporting library based on JasperReports which lets you create sophisticated reports at the lowest way without need to use visual designer, main benefit of this library is dynamic report design.
  • SWTJasperViewer, an open source reusable component that can be embedded in any SWT/JFace application such as Eclipse.
  • Report Integration Framework, an open source report abstraction layer.
  • five Eclipse plug-ins that provide report designing and debugging capabilities, including:
    • JasperSoft Studio (Still in Alpha) is a rewrite of iReports in Eclipse
    • a commercial Eclipse plug-in called JasperAssistant. The JasperAssistant plug-in is built using SWTJasperViewer.
  • WebReportBuilder, an open source Java EE web application that allows web based developers and non developers to create basic and advanced Reports based on JasperReports to be used as a Web Report Server.
  • OpenReports, a Java EE web application that provides advanced report server capabilities with support for four open source reporting engines: JasperReports, JFreeReport, JXLS, and Eclipse BIRT.
  • JasperTags, a JSP tag library for easy inclusion of reports in web applications.
  • Plazma Report Designer, an open source JasperReports designer plugin for Eclipse.
  • Aspose.Words for JasperReports, for converting reports from JasperReports and JasperServer to Word formats.
  • Aspose.Slides for JasperReports, for converting to PowerPoint PPT and PPS formats.
  • The Information Management System for Mine Action (IMSMA) uses JasperReports for its reporting capability. It is the most commonly used planning software for humanitarian demining.
Sample
Now I'm going to take a sample and describe more about JasperReports via this sample. I've had a post about JQGrid plugin. I'm going to extend the sample of that post. I'll make a report page for file list result.

JasperReportView class
I make a class called JasperReportView to handle JasperReports needed codes. Here is the source code:
public class JasperReportView {

    public JasperReportView(HttpServletResponse response) {
        this.response = response;
    }

    HttpServletResponse response;
    JasperReport jasperReport;
    JasperPrint jasperPrint;
    JasperDesign jasperDesign;
    byte[] pdfReport;

    public void renderPdfByJasper(String jasper, Map parameters) throws IOException, JRException, SQLException {
        InputStream is = this.getClass().getResource(jasper).openStream();
        try {
            jasperReport = (JasperReport) JRLoader.loadObject(is);
            jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, SpringUtils.<DriverManagerDataSource>getBean("dataSource").getConnection());
            pdfReport = JasperExportManager.exportReportToPdf(jasperPrint);
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.addHeader("Content-Disposition", "attachment; filename=report.pdf");
            OutputStream out = response.getOutputStream();
            out.write(pdfReport);
            out.close();
        }
        finally {
            is.close();
        }
    }

    public void renderPdfByJrxml(String jrxml, Map parameters) throws IOException, JRException, SQLException {
        InputStream is = this.getClass().getResource(jrxml).openStream();
        try {
            jasperDesign = JRXmlLoader.load(is);
            jasperReport = JasperCompileManager.compileReport(jasperDesign);
            jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, SpringUtils.<DriverManagerDataSource>getBean("dataSource").getConnection());
            pdfReport = JasperExportManager.exportReportToPdf(jasperPrint);
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.addHeader("Content-Disposition", "attachment; filename=report.pdf");
            OutputStream out = response.getOutputStream();
            out.write(pdfReport);
            out.close();
        }
        finally {
            is.close();
        }
    }

    public void renderHtmlByJasper(String jasper, Map parameters) throws IOException, JRException, SQLException {
        ...
    }

    public void renderHtmlByJrxml(String jrxml, Map parameters) throws IOException, JRException, SQLException {
        ...
    }

    public void renderCsvByJasper(String jasper, Map parameters) throws IOException, JRException, SQLException {
        ...
    }

    public void renderCsvByJrxml(String jrxml, Map parameters) throws IOException, JRException, SQLException {
        ...
    }
}
As you see the red lines are the code to work with .jasper and the blue lines are the code to work with .jrxml.
As I mentioned the .jrxml files should be compiled at run time so it will take more time.
CSV and Html version export look likes Pdf version.The green lines are the codes to download the exported files.

How to use JasperReportView class
I should just make an object instance from JasperReportView class and use any method we need. The class needs HttpServletResponse as constructor parameter. Because it should download the exported file in its methods. Every method needs file path and report needed parameters as a Map.
FileController class is a class to handle file page actions. Take a look here:
@Controller
@Scope("prototype")
@RequestMapping("/file")
public class FileController extends BaseController {
...

    @RequestMapping("/pdf")
    public void pdfShow() throws IOException, SQLException, JRException {
        JasperReportView jrv = new JasperReportView(getResponse());
        if (getParentFolder().getId() == null) {
//        jrv.renderPdfByJrxml("/com/ucs/file/file-root.jrxml", getReportParams());
            jrv.renderPdfByJasper("/com/ucs/file/file-root.jasper", getReportParams());
        } else {
//        jrv.renderPdfByJrxml("/com/ucs/file/folder-file.jrxml", getReportParams());
            jrv.renderPdfByJasper("/com/ucs/file/folder-file.jasper", getReportParams());
        }
    }

    @RequestMapping("/csv")
    public void csvShow() throws IOException, SQLException, JRException {
        JasperReportView jrv = new JasperReportView(getResponse());
        if (getParentFolder().getId() == null) {
//        jrv.renderCsvByJrxml("/com/ucs/file/file-root.jrxml", getReportParams());
            jrv.renderCsvByJasper("/com/ucs/file/file-root.jasper", getReportParams());
        } else {
//        jrv.renderCsvByJrxml("/com/ucs/file/folder-file.jrxml", getReportParams());
            jrv.renderCsvByJasper("/com/ucs/file/folder-file.jasper", getReportParams());
        }
    }

    @RequestMapping("/html")
    public void htmlShow() throws IOException, SQLException, JRException {
        JasperReportView jrv = new JasperReportView(getResponse());
        if (getParentFolder().getId() == null) {
//        jrv.renderHtmlByJrxml("/com/ucs/file/file-root.jrxml", getReportParams());
            jrv.renderHtmlByJasper("/com/ucs/file/file-root.jasper", getReportParams());
        } else {
//        jrv.renderHtmlByJrxml("/com/ucs/file/folder-file.jrxml", getReportParams());
            jrv.renderHtmlByJasper("/com/ucs/file/folder-file.jasper", getReportParams());
        }
    }


    public Map<String, Object> getReportParams() {
        Map<String, Object> params = new HashMap();
        params.put("parentFolderId", getParentFolder().getId());
        params.put("ownerId", getCurrentUser().getId());
        return params;
    }
...

}
The report needs two parameters:
  • parentFolderId
  • ownerId
So I put them in a map and pass it to the JasperReportView methods(red lines). I do it in getReportParams method(green lines).

Appendix

1. SpringUtils Class
It's a very useful class to provide you Spring Context. On this way you can have spring beans in you java code. This class should Implements ApplicationContextAware class and setApplicationContext method. Take look here:
public class SpringUtils implements ApplicationContextAware {
    private static ApplicationContext context;

    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    public static <T> T getBean(String beanName) {
        return (T) context.getBean(beanName);
    }

    public static <T> Map<String, T> getBeans(Class clazz) {
        return (Map<String, T>) context.getBeansOfType(clazz);
    }

    public static HttpSession getCurrentSession() {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        return attr.getRequest().getSession(true); // true == allow create
    }

    public static HttpServletRequest getCurrentRequest() {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        return attr.getRequest();
    }
}

As you see the setApplicationContext method will pass you a context in its parameter. I take it in the class static field. So I will use it in getBean and getBeans methods. This class also provide you current session and current request as static methods(The green lines). So I can use them anywhere I need session and request.

2. JRXML files
jrxml is JasperReports xml file. Reports elements like page header, footer, Grid header, repeat items, ... will be determined in it. Here file-root.jrxml example is available:
<jasperReport
         name="file"
         columnCount="1"
         printOrder="Vertical"
         orientation="Portrait"
         pageWidth="595"
         pageHeight="842"
         columnWidth="535"
         columnSpacing="0"
         leftMargin="30"
         rightMargin="30"
         topMargin="20"
         bottomMargin="20"
         whenNoDataType="NoPages"
         isTitleNewPage="false"
         isSummaryNewPage="false">
    <property name="ireport.scriptlethandling" value="0" />
    <property name="ireport.encoding" value="UTF-8" />
    <import value="java.util.*" />
    <import value="net.sf.jasperreports.engine.*" />
    <import value="net.sf.jasperreports.engine.data.*" />
    <reportFont name="bnazanin" isDefault="false" fontName="Nazanin" size="14" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="NAZ___SF.TTF" pdfEncoding="Identity-H" isPdfEmbedded="true"/>

    <parameter name="parentFolderId" isForPrompting="true" class="java.lang.Long">
        <defaultValueExpression ><![CDATA[new Long(0)]]></defaultValueExpression>
    </parameter>
    <parameter name="ownerId" isForPrompting="true" class="java.lang.Long">
        <defaultValueExpression ><![CDATA[new Long(0)]]></defaultValueExpression>
    </parameter>
    <queryString><![CDATA[SELECT `name`, `is_file` FROM `tb_file` where owner_id = $P{ownerId} and parent_file_id IS NULL;]]></queryString>

    <field name="name" class="java.lang.String"/>
    <field name="is_file" class="java.lang.String"/>

        <background>
            <band height="0"  isSplitAllowed="true" >
            </band>
        </background>
        <title>
            <band height="50"  isSplitAllowed="true" >
            </band>
        </title>
        <pageHeader>
            <band height="36"  isSplitAllowed="true" >
            </band>
        </pageHeader>
        <columnHeader>
            <band height="75"  isSplitAllowed="true" >
                <staticText>
                    <reportElement
                        x="4"
                        y="52"
                        width="97"
                        height="20"
                        key="staticText-2"/>
                    <box topBorder="Thin" topBorderColor="#000000" leftBorder="Thin" leftBorderColor="#000000" rightBorder="Thin" rightBorderColor="#000000" bottomBorder="Thin" bottomBorderColor="#000000"/>
                    <textElement>
                        <font reportFont="bnazanin"/>
                    </textElement>
                <text><![CDATA[File Name]]></text>
                </staticText>
                <staticText>
                    <reportElement
                        x="101"
                        y="52"
                        width="97"
                        height="20"
                        key="staticText-3"/>
                    <box topBorder="Thin" topBorderColor="#000000" leftBorder="Thin" leftBorderColor="#000000" rightBorder="Thin" rightBorderColor="#000000" bottomBorder="Thin" bottomBorderColor="#000000"/>
                    <textElement>
                        <font reportFont="bnazanin"/>
                    </textElement>
                <text><![CDATA[File type]]></text>
                </staticText>
            </band>
        </columnHeader>
        <detail>
            <band height="25"  isSplitAllowed="true" >
                <textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
                    <reportElement
                        x="3"
                        y="0"
                        width="95"
                        height="18"
                        key="textField"/>
                    <box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>
                    <textElement>
                        <font reportFont="bnazanin"/>
                    </textElement>
                <textFieldExpression   class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
                </textField>
                <textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None"  hyperlinkTarget="Self" >
                    <reportElement
                        x="99"
                        y="1"
                        width="100"
                        height="18"
                        key="textField"/>
                    <box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>
                    <textElement>
                        <font reportFont="bnazanin"/>
                    </textElement>
                <textFieldExpression   class="java.lang.String"><![CDATA[$F{is_file}]]></textFieldExpression>
                </textField>
            </band>
        </detail>
        <columnFooter>
            <band height="30"  isSplitAllowed="true" >
            </band>
        </columnFooter>
        <pageFooter>
            <band height="50"  isSplitAllowed="true" >
            </band>
        </pageFooter>
        <lastPageFooter>
            <band height="50"  isSplitAllowed="true" >
            </band>
        </lastPageFooter>
        <summary>
            <band height="50"  isSplitAllowed="true" >
            </band>
        </summary>
</jasperReport>

Source Code
Now you can download the sample and try it yourselves. You can download the needed jar files from this sample. You need to copy all jar files to [Project Root]/lib path.
The application database script is available in [app-root]/db/filerepository.sql. you can restore it in your mysql server. the connection datasource properties is in [app-root]/src/database.properites. And after you deploy the project in your application server (like tomcat) the home page will be: http://localhost:8080/home/view.html also file list page is: http://localhost:8080/file/list.html

Make sure JaperReports needed files(file-root.jasper, file-root.jrxml, folder-file.jasper and folder-file.jrxml) exist in your deployment path. If not copy them into WEB-INF/classes/com/ucs/file/ path by yourselves.

the admin user specification is:
username: administrator
password: 123456
you can use it to login to the site for the first time.



all rights reserved by Mostafa Rastgar and Programmer Assistant weblog

Monday, April 18, 2011

JQuery-Plugin, Validators

Hey...

Here I'm going to describe a very useful jquery plugin for every enterprise applications. This is jquery validation plugin. I've extended this plugin and add some features to it. But the first, concept detail.

Concept Detail

A validation should prevent page from submitting if the client input values don't follow validation rules. It's a simple model of validation. But there are much more points which should be considered. A page may contains more than one action but only some of the rules should be performed for any actions. For example for a simple signup page have two methods to save entry. signup action and temporary save action. Some fields are required for signup but not for temporary save and so on.

The second point is, all validation rules are not just required rule. There are different kinds of rules. Some of them are here:
  • required
  • integer
  • decimal
  • gt
  • ge
  • lt
  • le
  • eq
  • email
  • number
  • maxLength
  • minLength
  • max
  • min
  • remote
  • custom
  • ...
Our validation method should support different kinds of validation rules.

The third point is, all validation should not be shown as an error. Some of them should be shown as a warning. A warning is not an incompatibility or at least does not make a fatal error. But client should be aware of it. For example for registration you should enter your email in correct format. But for temporary save it is not necessary. Because finally you should signup it and in signup email format validation prevents from signup if incompatibility exist.

The final point is custom message. The developer should be able to change the default message of validation and inject its own message for any incompatibility happens.

Validation Plugin Detail
General use of validation is like here:
$('#formId').validate({
rules:{inputname:{ruleName:ruleValue, ...},
...},
messages:{
'inputname':{ruleName:$.validator.format('This is custom message'),...},
...},
validationGroup:'validationGroup',
warningGroup:'warningGroup',
clickedButton:btnObject});
  • 'inputname' is your page input name
  • 'ruleName' is one of the supported rules: required, number, date, ....
  • 'ruleValue' depends on type of selected rule: required:true, max:20, date:true, minLength:50, between:[10,20], ... . It is simple value. But for grouping use, value can be a collection. Take a look here:
    'testinput':{required:{value:true, validationGroup:'signup', warningGroup:'tempSave'}}
    This collection has only three parts:
    • value: The value of the related rule
    • validationGroup:A simple text containing validation groups. More than one validation group is supported but should be separated with ','. For example: validationGroup:'signup,tempSave'
    • warningGroup: A simple text containing warning groups. More than one warning group is supported but should be separated with ','. For example: warningGroup:'signup,tempSave'
    If the value is simple(for example true or [10,20]) it means this rule should be checked in every actions of the page and grouping check is not needed.
  • messages is used for custom messages
  • validationGroup is used to validate the inputs which their rules validationGroup contains this validationGroup
  • warningGroup is used to validate the inputs which their rules warningGroup contains this warningGroup

Here are available rules for an input with name of "testinput":
'testinput':{range:[10,30]}
rule namesupported valuedescriptionexample
requiredtrue/flaseThe input should have value'testinput':{required:true}
between['#firstInputId',
'#secondInputId']
The input should have value be between 'firstInputId' value and 'secondInputId' value'testinput':{between:['#testinput1', '#testinput2']}
decimaltrue/flaseThe input should have decimal value'testinput':{decimal:true}
emailtrue/flaseThe input value should follow email format 'testinput':{email:true}
eq['#compareInputId', 'compareInputLabel']The input should equal to 'compareInputId' and if not, uses 'compareInputLabel' in error massage'testinput':{eq:['#testInput1', 'first name']}
ge['#compareInputId',
'compareInputLabel']
The input should greater equal to 'compareInputId' and if not, uses 'compareInputLabel' in error massage'testinput':{ge:['#testInput1', 'first name']}
gt['#compareInputId',
'compareInputLabel']
The input should greater than 'compareInputId' and if not, uses 'compareInputLabel' in error massage'testinput':{gt:['#testInput1', 'first name']}
integertrue/flaseThe input should have integer value'testinput':{integer:true}
le['#compareInputId',
'compareInputLabel']
The input should less equal to 'compareInputId' and if not, uses 'compareInputLabel' in error massage'testinput':{le:['#testInput1', 'first name']}
lt['#compareInputId',
'compareInputLabel']
The input should less than 'compareInputId' and if not, uses 'compareInputLabel' in error massage'testinput':{lt:['#testInput1', 'first name']}
maxlengthinteger numberThe input value length should be less than input integer number.'testinput':{maxlength:10}
maxinteger numberThe input value should be less than input integer number'testinput':{max:20}
minlengthinteger numberThe input value length should be more than input integer number.'testinput':{minlength:100}
mininteger numberThe input value should be more than input integer number'testinput':{min:80}
neq['#compareInputId', 'compareInputLabel']The input should not equal to 'compareInputId' and if not, uses 'compareInputLabel' in error massage'testinput':{neq:['#testInput1', 'first name']}
rangelength[integer number1,
integer number2]
The input value length should be between integer number1 and integer number 2'testinput':{rangelength:[10,30]}
range[integer number1,
integer number2]
The input value should be between integer number1 and integer number 2'testinput':{range:[10,30]}
custom---Custom validation doesn't follow the other validation methods. you should first write your own javascript function. The javascript function has three parameters: value,element, parameter. Then you should register your function in jquery validation this way: $.validator.addMethod('method name text', method name, jQuery.validator.format('error message'));
function customjavascript(value, element, parameter){
if(value == $('#input1').val()*10){
return true;
} else {
return false;
}
}
$.validator.addMethod('customjavascript',
customjavascript,
jQuery.validator.format('The input value should equal to input1 * 10'));
remote{url:'url string',
type:'get'or'post'
data:{
pname:pvalue
,...}}
Calls a server side method via ajax. It also posts parameters(pname=pvalue) with its call. We can use parameters in server side in request parameter object.
If server side method returns empty String, it means it passes the validator elsewhere It does not pass the validator and return string is the message which should be shown in client.
'testinput':{remote:{url:'home/remoteCheck.html',
type:'post',
data:{'input1':$('#input1').val(),
'input2':$('#input2').val()}}}
@RequestMapping(value = "/home/remoteCheck")
@ResponseBody
public String remoteCheck(HttpServletRequest request){
if(request.getParameter('input1') == request.getParameter('input2')){
return "input1 and input2 should be equal together"
}
return "";
}

Sample

You can download the sample from here. The needed js and css files are in that zipped file.
Sample Detail
It is a simple sign up form. You should enter some information in this form. The form has two actions:
  • signup: It is supposed that the input data is saved and accepted by the client.
  • tempSave: It is supposed that the input data is saved temporarily. But is not final accepted by the client.
Any actions has its own validation some of the validations are warning in any action mode.
For more information refer to the sample.
Sample Validation Method
A javascript function handles validation configuration.
function postFunc(validationGroupParam, warningGroupParam, btn) {
            var settings = $('#signupform').validate().settings;
            $.extend(settings, {
                rules:{
                    'fname':{required:true},
                    'lname':{required:true},
                    'email':{required:true, email:{value:true, validationGroup:'signup', warningGroup:'tempSave'}},
                    'sDate':{date:true, le:{value:['#eDate', 'end date'], validationGroup:'signup'}},
                    'eDate':{date:true, required:{value:true, validationGroup:'signup', warningGroup:'tempSave'}},
                    'age':{number:true, required:{value:true, validationGroup:'signup', warningGroup:'tempSave'}, min:{value:18, validationGroup:'signup'}}
                },
                messages:{'eDate':{required:$.validator.format('account end date is required...')}},
                validationGroup:validationGroupParam,
                warningGroup:warningGroupParam,
                clickedButton:btn
            });
        }
This method will be raised in buttons click:
<input type="submit" value="signup" name="signup" onclick="postFunc('signup', 'signup', this);"/>
<input type="submit" value="tempSave" name="tempSave" onclick="postFunc('tempSave', 'tempSave', this);"/>
Sample Internationalization
This plugin supports multy languages even in direction. For example in Persian language the direction is right to left. There are some alternative scripts to handle this:
   <script type="text/javascript" src="js/jquery-1.5.1.min.js"></script>
    <script type="text/javascript" src="js/jquery.validate.js"></script>
    <!--<script type="text/javascript" src="js/jquery.validate_fa.js"></script>-->
    <script type="text/javascript" src="js/additional-methods.js"></script>
    <script type="text/javascript" src="js/messages.js"></script>
    <!--<script type="text/javascript" src="js/messages_fa.js"></script>-->
    <script type="text/javascript" src="js/jquery.tooltip.js"></script>
    <script type="text/javascript" src="js/javascriptutil.js"></script>
    <link rel="stylesheet" href="css/screen.css">
    <!--<link rel="stylesheet" href="css/screen_fa.css">-->
js/jquery.validate_fa.js, js/messages_fa.js, css/screen_fa.css are alternative files of js/jquery.validate.js, js/messages.js, css/screen.css files. You can change them with each other to change the validation language.



all rights reserved by Mostafa Rastgar and Programmer Assistant weblog

Wednesday, April 13, 2011

Groovy+Spring Configuration

Hey...

Spring 2.0+ introduces comprehensive support for using classes and objects that have been defined using a dynamic language (such as JRuby) with Spring.
This support allows you to write any number of classes in a supported dynamic language, and have the Spring container transparently instantiate, configure and dependency inject the resulting objects.
The dynamic languages currently supported are:
  • JRuby
  • Groovy
  • BeanShell
Here I'm going to describe about Groovy itself and its configuration in spring. Other dynamic languages are similar to this.

1. Example Detail

I'm going to create a sample to do major operation of typical calculator with groovy and leave it open to be upgratable to advance operations by groovy. So you will be able to add more operation to it. The application has two major parts.
  • Groovy Script In File(The gray lines in grid of Image 1)
    • Add
    • Subtract
    • Multiply
    • Divide
  • Groovy Script In Database(The black lines in grid of Image 1)
    • Power
    • Factorial
    • ...(You can add more operation dynamically)
You can add more operations without restart the application. This is the best advantage of dynamic languages like groovy.
Image 1
2. Spring Configuration
The only needed spring configuration is to create a bean from groovy script file. Take look here:
<?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:lang="http://www.springframework.org/schema/lang"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
    <lang:groovy  id="Calculator" refresh-check-delay="1000" scope="prototype" script-source="classpath:/com/calculator/CalculatorImpl.groovy"></lang:groovy>
</beans>
As you see I create a bean called "Calculator" from CalculatorImpl.groovy file.
Tag attributes and body:
2.1 refresh-check-delay
The delay (in milliseconds) between checks for updated sources when using the refreshable beans feature.
2.2 Scope
The scope of this scripted bean: typically "singleton" (one shared instance, which will be returned by all calls to getBean with the given id), or "prototype" (independent instance resulting from each call to getBean). Default is "singleton".
Singletons are most commonly used, and are ideal for multi-threaded service objects. Further scopes, such as "request" or "session", might be supported by extended bean factories (e.g. in a web environment).
2.3 script-source
The resource containing the script for the dynamic language-backed bean.
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
2.4 property(body tag)
Dynamic language-backed bean definitions can have zero or more properties.Property elements correspond to JavaBean setter methods exposed by the bean classes. Spring supports primitives, references to other beans in the same or related factories, lists, maps and properties.
2.5 inline-script
The source code for the dynamic language-backed bean. For example:
    <lang:groovy  id="Calculator" refresh-check-delay="1000" scope="prototype">
        <lang:inline-script>
            package com.calculator;
            class TestClass{
              public string showMessage() {
                return "Hello world";
              }
            }
        </lang:inline-script>
    </lang:groovy>






Here is the CalculatorImpl.groovy detail:
package com.calculator;

class CalculatorImpl implements Calculator{
  public int add(int val1, int val2) {
    return val1 + val2;
  }

  public int multiply(int val1, int val2) {
    return val1 * val2;
  }

  public int subtract(int val1, int val2) {
    return val1 - val2;
  }

  public int divide(int val1, int val2) {
    return val1 / val2;
  }
}
As you see the groovy file is a simple class containing some simple methods. After the Spring configuration you can have it from spring context and use it like other java classes. To use this class in your java code, you should have a type of it. You are not able to use its type(CalculatorImpl) directly. Because This type is defined in groovy script not in your java class hierarchy. So I this problem by creating an interface. The "CalculatorImpl" implements "Calculator" interface so is type of "Calculator". In my java codes I can define a variable typed "Calculator" and Initiate it by "CalculatorImpl" via spring context.
Calcualtor.java:
package com.calculator;

public interface Calculator {
    int add(int val1, int val2);

    int multiply(int val1, int val2);

    int subtract(int val1, int val2);

    int divide(int val1, int val2);
}
And here is the use of the CalculatorImpl in CalculatorController.java:
package com.calculator;

import org.springframework.stereotype.Controller;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import com.base.controller.BaseController;
import com.rule.service.RuleService;
import com.rule.Rule;
import com.groovy.GroovyProxy;

import javax.script.ScriptException;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

@Controller
@Scope("prototype")
@RequestMapping("/calculator")
public class CalculatorController extends BaseController {
    Integer input1;

    Integer input2;

    Integer result;

    List<Rule> ruleList;

    Long ruleId;

    @Autowired
    RuleService ruleService;

    @Autowired
    Calculator calculator;

    public Integer getInput1() {
        return input1;
    }

    public void setInput1(Integer input1) {
        this.input1 = input1;
    }

    public Integer getInput2() {
        return input2;
    }

    public void setInput2(Integer input2) {
        this.input2 = input2;
    }

    public Integer getResult() {
        return result;
    }

    public void setResult(Integer result) {
        this.result = result;
    }

    public List<Rule> getRuleList() {
        return ruleList;
    }

    public void setRuleList(List<Rule> ruleList) {
        this.ruleList = ruleList;
    }

    public Long getRuleId() {
        return ruleId;
    }

    public void setRuleId(Long ruleId) {
        this.ruleId = ruleId;
    }

    @RequestMapping("view")
    public String view() {
        ruleList = ruleService.findByAll();
        return "calculator.view";
    }

    @RequestMapping("add")
    public String add() {
        result = calculator.add(input1, input2);
        return view();
    }

    @RequestMapping("subtract")
    public String subtract() {
        result = calculator.subtract(input1, input2);
        return view();
    }

    @RequestMapping("multiply")
    public String multiply() {
        result = calculator.multiply(input1, input2);
        return view();
    }

    @RequestMapping("divide")
    public String divide() {
        result = calculator.divide(input1, input2);
        return view();
    }

    @RequestMapping("customrule")
    public String customRule() throws ScriptException {
        Rule rule = ruleService.findById(ruleId);
        GroovyProxy groovyProxy = new GroovyProxy();
        Map<String, Integer> params = new HashMap();
        params.put("val1", input1);
        params.put("val2", input2);
        result = (Integer) groovyProxy.execute(rule.getRuleScript(), params);

        return view();
    }
}
As you see I've just made "Calculator calculator" autowired like "RuleService ruleService". Then I've used it just like other classes.
3. Groovy Live Usage
You can add more scripts dynamically into database then use it in the application. To do that, I create an entity called Rule:
package com.rule;

import javax.persistence.*;

@Entity
@Table(name = "tb_rules")
public class Rule {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    Long id;

    @Column(name = "rule_name")
    String ruleName;

    @Column(name = "rule_script")
    String ruleScript;

    public Long getId() {
        return id;
    }

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

    public String getRuleName() {
        return ruleName;
    }

    public void setRuleName(String ruleName) {
        this.ruleName = ruleName;
    }

    public String getRuleScript() {
        return ruleScript;
    }

    public void setRuleScript(String ruleScript) {
        this.ruleScript = ruleScript;
    }
}
I fetch all of scripts from database and show them to user. User can execute whatever she/he wants. To execute the fetched record I create "GroovyProxy" calss:
package com.groovy;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.Map;

public class GroovyProxy {
    ScriptEngineManager factory;
    ScriptEngine engine;

    public GroovyProxy() {
        factory = new ScriptEngineManager();
        engine = factory.getEngineByName("groovy");
    }

    public Object execute(String script, Map params) throws ScriptException {
        for (Object key : params.keySet()) {
            engine.put(key.toString(), params.get(key));
        }
        return engine.eval(script);
    }
}
This class creates a groovy engine(red lines) first then execute the passed method(blue lines). The needed parameters of the script is passed via the execute method parameter.
Here are some available groovy scripts in database:
  • Power:
    if(val2==0){
    return 1;
    } else {
    int result = 1;
    for(int i in 1..val2){
    result = result * val1;
    }
    return result;
    }
  • Factorial:
    int result = 1;
    for(int i in val1..1){
    result = result * i;
    }
    return result;
The red parameters are the passed parameters(Map params) in "execute" method of "GroovyProxy" class.
You can find the use of "GroovyProxy" class in customRule method of "CalculatorController" class(the blue lines).

Source Code
It's the time to download the source code. You can also download the application war file to deploy it in your application server directly. After deployment, the start page will be: http://localhost:8080/calculator/view.htm. The database script is [App Root]/db/groovydb.sql. You can restore it into your mysql server. The connection datasource detail is: [App Root]/src/database.properties



all rights reserved by Mostafa Rastgar and Programmer Assistant weblog