Saturday, July 14, 2012

ZK: Modify tooltiop on gantt chart


Introduction

Chart is a component of ZK which can draw various kind of chart, in gantt chart it will show some default tooltip on the 'bar'.

This post is about how to change the tooltip of bars to customized value.

The ZUL Page

modify_tooltip_on_gantt_chart.zul

<zk xmlns:w="client">
    <!-- prepare model -->
    <zscript><![CDATA[
        import org.zkoss.zul.GanttModel.GanttTask;
             
            public Date date(int year, int month, int day) {
                final java.util.Calendar calendar = java.util.Calendar.getInstance();
                calendar.set(year, month-1, day);
                final Date result = calendar.getTime();
                return result;
            }
            //series, task (task description, start, end, complete percentage)
            GanttModel ganttmodel = new GanttModel();
            ganttmodel.addValue("Scheduled", new GanttTask("Write Proposal", date(2008,4,1), date(2008,4,5), 0.1));
            ganttmodel.addValue("Scheduled", new GanttTask("Obtain Approval", date(2008,4,9), date(2008,4,9), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Requirements Analysis", date(2008,4,10), date(2008,5,5), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Design Phase", date(2008,5,6), date(2008,5,30), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Design Signoff", date(2008,6,2), date(2008,6,2), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Alpha Implementation", date(2008,6,3), date(2008,7,31), 0.2));
            ganttmodel.addValue("Scheduled", new GanttTask("Design Review", date(2008,8,1), date(2008,8,8), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Revised Design Signoff", date(2008,8,10), date(2008,8,10), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Beta Implementation", date(2008,8,12), date(2008,9,12), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Testing", date(2008,9,13), date(2008,10,31), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Final Implementation", date(2008,11,1), date(2008,11,15), 0.0));
            ganttmodel.addValue("Scheduled", new GanttTask("Signoff", date(2008,11,28), date(2008,11,30), 0.0));
             
            ganttmodel.addValue("Actual", new GanttTask("Write Proposal", date(2008,4,1), date(2008,4,3), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Obtain Approval", date(2008,4,9), date(2008,4,9), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Requirements Analysis", date(2008,4,10), date(2008,5,15), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Design Phase", date(2008,5,15), date(2008,6,17), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Design Signoff", date(2008,6,30), date(2008,6,30), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Alpha Implementation", date(2008,7,1), date(2008,9,12), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Design Review", date(2008,9,12), date(2008,9,22), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Revised Design Signoff", date(2008,9,25), date(2008,9,27), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Beta Implementation", date(2008,8,12), date(2008,9,12), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Testing", date(2008,10,31), date(2008,11,17), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Final Implementation", date(2008,11,18), date(2008,12,5), 0.0));
            ganttmodel.addValue("Actual", new GanttTask("Signoff", date(2008,12,10), date(2008,12,11), 0.0));
    ]]></zscript>
    <chart id="gantt" title="Gantt Chart" width="700" height="400"
        model="${ganttmodel}"
        type="gantt" threeD="false" fgAlpha="128" dateFormat="yyyy/MM/dd" >
        <!-- override bind_ function to update the tooltip -->
        <attribute w:name="bind_"><![CDATA[
            function () {
                this.$bind_();
                var areas = jq('area'),
                    len = areas.length;
                if (len > 0) {
                    for (var i = 0; i < len; i++) {
                        var area = areas[i],
                            title;
                        // original format is 'percentage, start ~ end'
                        // extract the 'start' and 'end' to create new tooltip
                        if ((title = area.title) && title.indexOf(',') >= 0 && title.indexOf('~') >= 0) {
                            var range = title.split(',')[1].split('~'),
                                start = range[0].replace(/^\s\s*/, '').replace(/\s\s*$/, ''),
                                end = range[1].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    
                            // update title
                            area.title = 'Range: From ' + start + ' to ' + end;
                        }
                    }
                }
            }
    ]]></attribute>
    </chart>
</zk>


The Result



Reference
http://books.zkoss.org/wiki/ZK_Component_Reference/Diagrams_and_Reports/Chart


Download
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/WebContent/modify_tooltip_on_gantt_chart.zul

Friday, July 13, 2012

ZK Pivottable: Display Data in ZK Pivottable


Introduction

ZK Pivottable is a ZK addon component that can display data in summarized view as MS-Excel's pivottable. In this post, we will try to display some fake data in pivottable.

The Composer

TestComposer.java

package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import org.zkoss.pivot.PivotField;

import org.zkoss.pivot.impl.TabularPivotModel;

import org.zkoss.zk.ui.select.SelectorComposer;

/**
 * Tested with ZK 6.0.1 CE and ZK Pivottable 2.0.0
 *
 */
@SuppressWarnings("rawtypes")
public class TestComposer extends SelectorComposer {
    /**
     * generated serial version UID
     */
    private static final long serialVersionUID = -2897873399288955635L;
    private TabularPivotModel _pivotModel;

    /**
     * Get pivottable's model
     * @return TabularPivotModel the pivottable's model
     * @throws Exception
     */
    public TabularPivotModel getPivotModel () throws Exception {
        if (_pivotModel == null) {
            _pivotModel = new TabularPivotModel(getData(), getColumns());

            // assign rows, the order matches to the level of row node field
            _pivotModel.setFieldType("Row_Level_001", PivotField.Type.ROW);
            _pivotModel.setFieldType("Row_Level_002", PivotField.Type.ROW);
            _pivotModel.setFieldType("Row_Level_003", PivotField.Type.ROW);
            _pivotModel.setFieldType("Row_Level_004", PivotField.Type.ROW);

            // assign columns, the order matches to the level of column node field
            _pivotModel.setFieldType("Column_Level_001", PivotField.Type.COLUMN);
            _pivotModel.setFieldType("Column_Level_002", PivotField.Type.COLUMN);

            // assign datas, the order matches to the order of data field
            _pivotModel.setFieldType("Data_Field_001", PivotField.Type.DATA);
            _pivotModel.setFieldType("Data_Field_002", PivotField.Type.DATA);
            _pivotModel.setFieldType("Data_Field_003", PivotField.Type.DATA);
        }
        return _pivotModel;
    }
    /**
     * prepare the data for pivottable's model
     * The order of object put into data list matches
     * the order of column name's order
     * @return
     * @throws Exception
     */
    public List<List<Object>> getData() throws Exception {
        List<List<Object>> result = new ArrayList<List<Object>>();
        Random r = new Random();

        for (int i = 0; i < 10000; i++) {
            List<Object> data = new ArrayList<Object>();
            data.add("Row_Level_001 - " + (r.nextInt(10) + 1));
            data.add("Row_Level_002 - " + (r.nextInt(10) + 1));
            data.add("Row_Level_003 - " + (r.nextInt(10) + 1));
            data.add("Row_Level_004 - " + (r.nextInt(10) + 1));
            data.add("Column_Level_001 - " + (r.nextInt(10) + 1));
            data.add("Column_Level_002 - " + (r.nextInt(10) + 1));
            data.add(r.nextInt(10000));
            data.add(r.nextDouble() * 10000.0);
            data.add(r.nextInt(100));
            result.add(data);
        }
        return result;
    }
    /**
     * prepare columns name for pivottable's model
     * @return
     */
    public List<String> getColumns() {
        return Arrays.asList(new String[]{
                "Row_Level_001", "Row_Level_002", "Row_Level_003", "Row_Level_004",
                "Column_Level_001", "Column_Level_002",
                "Data_Field_001", "Data_Field_002", "Data_Field_003"
        });
    }
    
    
}


Here only simply add some fake data / columns to pivot model.
The order of data will matches to the order of column automatically.

The ZUL Page

index.zul

<zk>
    <!-- Tested with ZK 6.0.1 CE and ZK Pivottable 2.0.0 -->
    <!-- window, apply a SelectorComposer -->
    <window id="win" xmlns:w="client"
        apply="test.TestComposer">
        <!-- pivottable, get model from window's composer -->
        <pivottable id="pivottable" model="${win$composer.pivotModel}" />
    </window>
</zk>


The Result
View the demo flash on line
http://screencast.com/t/C2CxL4aeNHmZ

You can find the flash file at github:
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/addon/DisplayDataInPivottable.swf

Reference
http://books.zkoss.org/wiki/ZK_Pivottable_Essentials

Download
The full project is at github
https://github.com/benbai123/ZK_Practice/tree/master/Components/projects/Addon_Practice/PivottableTest/DisplayDataInPivottable

Sunday, July 8, 2012

JSP Custom Tag: Nested Tags


Introduction

In the previous post (http://ben-bai.blogspot.tw/2012/07/jsp-custom-tag-body-tag.html), we have implemented a body tag 'fadeoutBlock', in this post we will try the advanced body tag - 'Nested Tags' and implement a tag set 'tabbox, tabpanel'.

Pre-define

1. A tabbox can contain several tabpanels.
2. You can set the 'width' and 'height' of a tabbox.
3. A tabpanel can contains any JSP body content.
4. You can set the 'header' of a tabpanel.

The Program

Tabbox.java

package test.tag.custom;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;

/**
 * Simple tabbox with poor look and feel 
 */
public class Tabbox extends BodyTagSupport {
    private int _panelCnt = 0;
    private int _width = 100;
    private int _height = 100;
    private StringBuilder _headerContent = new StringBuilder("");
    private StringBuilder _bodyContent = new StringBuilder("");

    public void setWidth (int width) {
        _width = width;
    }
    public void setHeight (int height) {
        _height = height;
    }
    public int doStartTag() throws JspException {
        try {
            // output the out most area
            JspWriter out = pageContext.getOut();
            out.print("<div");
            out.print(" style=\"overflow: auto; width: "+_width+"px; height: "+_height+"px; border: 1px solid #CCCCCC;\"");
            out.print(">");
        } catch (Exception e) {
            throw new JspException("Error: IOException while writing to client");
        }

        // evaluate body content and output it directly
        return EVAL_BODY_INCLUDE;
    }

    public int doEndTag() throws JspException {
        try {
            JspWriter out = pageContext.getOut();
            // output the header/body of tabpanels
            out.print("<div>"+_headerContent.toString()+"</div>");
            out.print("<div style=\"margin: 10px; border: 1px solid #3648AE;\">"+_bodyContent.toString()+"</div></div>");
        } catch (Exception ex) {
            throw new JspException(ex.getMessage());
        }
        release();
        // continue evaluate page
        return EVAL_PAGE;
        
    }

    public void release() {
        // have to reset all field values since container may reuse this instance
        _panelCnt = 0;
        _width = 100;
        _height = 100;
        _headerContent.setLength(0);
        _bodyContent.setLength(0);
    }

    public void addHeaderContent (String content) {
        // called by Tabpanel, add header content
        String style = _panelCnt == 0? "background-color: gray;" : "background-color: transparent;";
        style += " margin-right: 5px; border: 1px solid #CCCCCC; border-bottom: 0px; cursor: pointer;";
        _headerContent.append("<span onclick=\""+showMatchedPanel()+"\" style=\""+style+"\">")
            .append(content)
            .append("</span>");
    }
    public void addBodyContent (String content) {
        // called by Tabpanel, add body contents
        String style = _panelCnt == 0? "" : "display: none;";
        _bodyContent.append("<div style=\""+style+"\">")
            .append(content)
            .append("</div>");
    }

    public void increaseCnt () {
        // called by Tabpanel, tell Tabbox the number of tabpanel is increased
        _panelCnt++;
    }

    // its better provided by a .js file
    private String showMatchedPanel () {
        // the javascript that executes while tabpanel's header clicked
        StringBuilder cmd = new StringBuilder();

        cmd.append("var headerContainer = this.parentNode,")
            .append("    headerArray = headerContainer.childNodes,")
            .append("    bodyContainer = headerContainer.nextSibling,")
            .append("    bodyArray = bodyContainer.childNodes,")
            .append("    ele, i, idx;")
            .append("for (i = 0; i < headerArray.length; i++) {")
            .append("    if ((ele = headerArray[i]) == this) {")
            .append("        ele.style.backgroundColor = 'gray';")
            .append("        idx = i;")
            .append("    } else")
            .append("        ele.style.backgroundColor = 'transparent';")
            .append("}")
            .append("for (i = 0; i < bodyArray.length; i++) {")
            .append("    if (i == idx)")
            .append("        bodyArray[i].style.display = 'block';")
            .append("    else")
            .append("        bodyArray[i].style.display = 'none';")
            .append("}");
        return cmd.toString();
    }
}

Tabbox provide the API's for tabpanels to add their header/body content and then output them properly with the appropriate javascript action while header clicked.

Tabpanel.java

package test.tag.custom;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;


/**
 * Simple tabpanel with poor look and feel
 */
public class Tabpanel extends BodyTagSupport {
    private String _header = new String("tab header");

    public void setHeader (String header) {
        _header = header;
    }

    public int doStartTag() throws JspException {
        // denotes evaluate body but do not output it, store it in buffer
        return EVAL_BODY_BUFFERED;
    }
    
    public int doEndTag() throws JspException {
        // find the parent tabbox
        Tabbox parent = (Tabbox)findAncestorWithClass(this, Tabbox.class);
        // get the buffered body content
        String body = getBodyContent().getString();
        // parent should not be null
        if(parent == null)
            throw new JspException("Tabpanel.doStartTag(): " + "No Tabbox ancestor");

        // fix empty body
        if (body == null || body.isEmpty())
            body = "&nbsp;"; // at least a space char
        // fix empty header
        if (_header == null || _header.isEmpty())
            _header = "&nbsp;"; // at least a space char
        // add header content to parent tabbox
        parent.addHeaderContent(_header);
        // add body content to parent tabbox
        parent.addBodyContent(body);
        parent.increaseCnt();
        release();

        return EVAL_PAGE;
        
    }
    
    public void release() {
        // have to reset all field values since container may reuse this instance
        _header = null;
    }
    
}

Tabpanel will store its body content in a buffer then pass it and header to Tabbox to render.

The tag definition

Add the fragment below to the tld file which already created from previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) then export jar as described in the previous post.


<tag>
    <!-- tag name -->
    <name>tabbox</name>
    <!-- tag class path -->
    <tagclass>test.tag.custom.Tabbox</tagclass>
    <!-- denotes the tag has JSP body content -->
    <bodycontent>JSP</bodycontent>
    <attribute>
        <!-- attribute name -->
        <name>width</name>
        <!-- required or not -->
        <required>false</required>
        <!-- el enable or not (true denotes can be eval at runtime) -->
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
        <!-- attribute name -->
        <name>height</name>
        <!-- required or not -->
        <required>false</required>
        <!-- el enable or not (true denotes can be eval at runtime) -->
        <rtexprvalue>false</rtexprvalue>
    </attribute>
</tag>
<tag>
    <!-- tag name -->
    <name>tabpanel</name>
    <!-- tag class path -->
    <tagclass>test.tag.custom.Tabpanel</tagclass>
    <!-- denotes the tag has JSP body content -->
    <bodycontent>JSP</bodycontent>
    <attribute>
        <!-- attribute name -->
        <name>header</name>
        <!-- required or not -->
        <required>false</required>
        <!-- el enable or not (true denotes can be eval at runtime) -->
        <rtexprvalue>false</rtexprvalue>
    </attribute>
</tag>

Test Page

tabboxTest.jsp

<%@ page isErrorPage="true" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<!-- use the custom taglib with prefix ct -->
<%@taglib prefix="ct" uri="http://test.tag.custom/jsp/impl/taglib"%>
<html>
    <head>
        <meta http-equiv="Content-Type" 
            content="text/html; charset=UTF-8"/>
        <title>EL Math Practice</title>
    </head>
    <body>
        <!-- the tabbox -->
        <ct:tabbox width="500" height="300">
            <!-- child tabpanels -->
            <ct:tabpanel header="Tab 1">
                this is the first panel of the tabbox
                <div style="height: 150px; width: 150px; background-color: red;"></div>
            </ct:tabpanel>
            <ct:tabpanel header="Tab 2">
                <div style="height: 200px; width: 200px; background-color: green;">
                    second panel
                </div>
            </ct:tabpanel>
            <ct:tabpanel header="Tab 3">
                the third panel
            </ct:tabpanel>
        </ct:tabbox>
    </body>
</html>


The Result

View the demo flash on line
http://screencast.com/t/e5QqxXQ1O

You can find the flash file at github:
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/demo_src/JSP/Custom_tag/tabbox_test.swf



Reference
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags.html


Download

The full project is at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/CustomTagPractice

Sunday, July 1, 2012

JSP Custom Tag: Body Tag


Introduction

In the previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) we implement a simple tag 'errMsg' to display some error message, in this post, we will create a body tag 'fadeoutBlock' to display content in a fade-out block.

A body tag is a JSP custom tag that has a body, the only difference between simple-tag and body-tag is body-tag will evaluate its body content but simple-tag will not.

Pre-define
The spec of the fadeoutBlock tag:
1. Can contain any JSP content in its body.
2. Attributes:
    style: the css style as normal html tag's style.
    styleClass: the css class as normal html tag's class.
    duration: the duration of fade-out action in milli seconds.
    step: the value that the opacity will be 'decreased' in each fade-out step.
3. Do fade-out while clicked.

The Program

FadeoutBlock.java

package test.tag.custom;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

/**
 * Fadeout Block JSP Custom Tag, body tag, can contain jsp content body.
 *
 */
public class FadeoutBlock extends TagSupport {

    private static final long serialVersionUID = 3563006227719937104L;
    private String _style = "background-color: CCBBEE;";
    private String _styleClass = null; //--css class
    private Integer _duration = 1000;
    private float _step = 0.1f;

    /**
     * tag attribute setter
     * @param style The style of this element
     */
    public void setStyle(String style){
        if (style != null && !style.isEmpty())
            _style = style;
    }
    /**
     * tag attribute setter
     * @param styleClass The css class of this element
     */
    public void setStyleClass(String styleClass){
        _styleClass = styleClass;
    }
    /**
     * tag attribute setter
     * @param duration The duration of fade-out action
     */
    public void setDuration (Integer duration) {
        if (duration > 0)
            _duration = duration;
    }
    /**
     * tag attribute setter
     * @param step The step value of each fade-out step
     */
    public void setStep (float step) {
        if (step > 0)
            _step = step;
    }
    /**
     * do start tag
     */
    @Override
    public int doStartTag() throws JspException {
        try {
            JspWriter out = pageContext.getOut();
            // output div's start tag, style, class and fadeOut function
            out.print("<div style=\""+_style+"\"");
            if (_styleClass != null)
                out.print(" class=\""+_styleClass+"\"");
            out.print("onclick=\""+fadeOut()+"\">");
        } catch (Exception e) {
            throw new JspException("Error: IOException while writing to client");
        }
        //-- continue process the body content
        return EVAL_BODY_INCLUDE;
    }
    /**
     * do end tag
     */
    @Override
    public int doEndTag() throws JspException {
        try {
            // output div's end tag
            pageContext.getOut().print("</div>");
        }
        catch (IOException ioe) {
            throw new JspException("Error: IOException while writing to client");
        }
        //-- continue process the page
        return EVAL_PAGE;
    }
    /**
     * The fadeOut function, its better provided from a js file.
     * @return String, the fadeOut function
     */
    private String fadeOut () {
        StringBuilder sb = new StringBuilder();
        sb.append("var ele = this, time = "+_duration / (1.0/_step)
                +", eStyle = ele.style, inc = "+_step+", timer, value;")
            .append("if (!eStyle.opacity) eStyle.opacity = 1;")
            .append("if (!ele.fo) ele.fo = setInterval(function () {")
            .append("if (eStyle.opacity > 0) {")
            .append("value = eStyle.opacity; eStyle.opacity -= inc;")
            .append("if (value == eStyle.opacity) value = eStyle.opacity = 0;")
            .append("else value = eStyle.opacity;")
            .append("eStyle.filter = 'alpha(opacity = ' + (value*100) + ')';")
            .append("} else clearInterval(ele.fo);")
            .append("}, time);");
        
        return sb.toString();
    }
}

The tag definition

Add the fragment below to the tld file which already created from previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) then export jar as described in the previous post.

<!-- fadeoutBlock tag -->
    <tag>
        <!-- tag name -->
        <name>fadeoutBlock</name>
        <!-- tag class path -->
        <tagclass>test.tag.custom.FadeoutBlock</tagclass>
        <!-- denotes the tag has JSP body content -->
        <bodycontent>JSP</bodycontent>
        <!-- attributes -->
        <attribute>
            <!-- attribute name -->
            <name>style</name>
            <!-- required or not -->
            <required>false</required>
            <!-- el enable or not (true denotes can be eval at runtime) -->
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
            <!-- attribute name -->
            <name>styleClass</name>
            <!-- required or not -->
            <required>false</required>
            <!-- el enable or not (true denotes can be eval at runtime) -->
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
            <!-- attribute name -->
            <name>duration</name>
            <!-- required or not -->
            <required>false</required>
            <!-- el enable or not (true denotes can be eval at runtime) -->
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
            <!-- attribute name -->
            <name>step</name>
            <!-- required or not -->
            <required>false</required>
            <!-- el enable or not (true denotes can be eval at runtime) -->
            <rtexprvalue>false</rtexprvalue>
        </attribute>
    </tag>

Test page

fadeoutBlockTest.jsp

<%@ page isErrorPage="true" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<!-- use the custom taglib with prefix ct -->
<%@taglib prefix="ct" uri="http://test.tag.custom/jsp/impl/taglib"%>
<html>
    <head>
        <meta http-equiv="Content-Type" 
            content="text/html; charset=UTF-8"/>
        <title>EL Math Practice</title>
        <style>
            .msg_block {
                position: absolute;
                left: 300px;
                top: 200px;
                width: 300px;
                height: 150px;
            }
        </style>
    </head>
    <body>
        <ct:fadeoutBlock styleClass="msg_block"
            duration="3000" step="0.05">
            <div style="margin: 20px; border: 1px solid #8463AE;">
                test message, click to fade-out
            </div>
        </ct:fadeoutBlock>
    </body>
</html>


The Result

View the demo flash on line
http://screencast.com/t/DAY7MfKaxtSg

You can find the flash file at github:
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/demo_src/JSP/Custom_tag/fadeOutBlock.swf


Reference
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags.html

Download
The full project is at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/CustomTagPractice

Monday, June 25, 2012

JSP Custom Tag: Simple Tag


Introduction

From official site:
A custom tag is a user-defined JSP language element. When a JSP page containing a custom tag is translated into a servlet, the tag is converted to operations on an object called a tag handler. The Web container then invokes those operations when the JSP page's servlet is executed.

Custom tags have a rich set of features. They can

Be customized via attributes passed from the calling page.
Access all the objects available to JSP pages.
Modify the response generated by the calling page.
Communicate with each other. You can create and initialize a JavaBeans component, create a variable that refers to that bean in one tag, and then use the bean in another tag.
Be nested within one another, allowing for complex interactions within a JSP page.

In short, it can encapsulate logic, style, script together and can make your page cleaner and do something more complex/powerful.

This post is about how to create a simple tag to display error message in specific style and do specific action.

Pre-define

The spec of the simple tag:
1. Output the given msg with default style "color: red; font-weight:bold;font-style:italic;", you can provide a css class to styleClass to override the default style.
2. Default alert msg+': '+msgDescription when clicked, you can provide a javascript function to onClick to override the default action.


The Program

ErrMsg.java

package test.tag.custom;

import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
/**
* Error Message JSP Custom Tag, simple tag, no tag body
*
*/
public class ErrMsg extends TagSupport {
    private static final long serialVersionUID = -2121640315534820214L;

    private String _msg; //-- error message
    private String _msgDescription; //-- error description
    private String _styleClass; //-- css class
    private String _onClick; // script to execute when clicked
    /**
     * tag attribute setter
     * @param msg The error messsage
     */
    public void setMsg(String msg) {
        _msg = msg;
    }
    /**
     * tag attribute setter
     * @param msgDescription The error description
     */
    public void setMsgDescription(String msgDescription) {
        _msgDescription = msgDescription;
    }
    /**
     * tag attribute setter
     * @param msgStyle The css class
     */
    public void setStyleClass(String styleClass){
        _styleClass = styleClass;
    }
    /**
     * tag attribute setter
     * @param onClick The script to execute while clicked
     */
    public void setOnClick (String onClick) {
        _onClick = onClick;
    }
    /**
     * do start tag, this function will be called when parsing &lt;errMsg msg=...&gt;
     */
    public int doStartTag() throws JspException {
        try {
            if(_msg != null){
                //-- output span's start tag
                pageContext.getOut()
                    .print("<span");

                //-- output default style or specified class
                if (_styleClass == null) {
                    pageContext.getOut()
                        .print(" style=\"color: red; font-weight:bold;font-style:italic;\"");
                } else {
                    pageContext.getOut()
                        .print(" class=\""
                                + _styleClass
                                + "\"");
                }
                //-- output default script or specified function
                if (_onClick == null) {
                    pageContext.getOut()
                        .print(" onclick=\"alert('"
                                + _msg
                                + (_msgDescription == null? "" : ": "+_msgDescription)
                                + "');\"");
                } else {
                    pageContext.getOut()
                        .print(" onclick=\""
                                + _onClick+"\"");
                }
                // finish span's start tag, output _msg.
                pageContext.getOut()
                    .print(">" + _msg);
            }
        } catch (Exception e) {
            throw new JspException("Error: IOException while writing to client");
        }
        // simple tag, no body.
        return SKIP_BODY;
    }
    /**
     * do end tag, this function will be called when parsing &lt;/errMsg&gt;
     */
    public int doEndTag() throws JspException {
        try {
            // output span's end tag
            pageContext.getOut().print("</span>");
        } catch (IOException ioe) {
            throw new JspException("Error: IOException while writing to client");
        }
        //-- continue processing the page
        return EVAL_PAGE;
    }
}


The tag definition

Create a folder META-INF at project root and write a xxx.tld in it, the content of the tld file is as below:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <!-- short name -->
    <shortname>ct</shortname>
    <!-- uri -->
    <uri>http://test.tag.custom/jsp/impl/taglib</uri>
    <!-- Message Tag -->
    <tag>
        <!-- tag name -->
        <name>errMsg</name>
        <!-- tag class path -->
        <tagclass>test.tag.custom.ErrMsg</tagclass>
        <!-- simple tag do not have body -->
        <bodycontent>empty</bodycontent>
        <!-- attributes -->
        <attribute>
            <!-- attribute name -->
            <name>msg</name>
            <!-- required or not -->
            <required>false</required>
            <!-- el enable or not (eval at runtime) -->
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <!-- attribute name -->
            <name>msgDescription</name>
            <!-- required or not -->
            <required>false</required>
            <!-- el enable or not (true denotes can be eval at runtime) -->
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>styleClass</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
            <name>onClick</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
    </tag>
</taglib>


Export jar

When the java file and tld file are ready, we have to export it as xxx.jar so we can use it in any web project:

1. Right click on java file -> Export



2. Select 'JAR file' -> Next



3. Check the folders 'src' and 'META-INF' are selected, choose export destination then click Finish.





Test it

After the jar is exported, we can copy it into WEB-INF/lib and write a jsp to test it.

errMsgTest.jsp

<%@ page isErrorPage="true" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<!-- use the custom taglib with prefix ct -->
<%@taglib prefix="ct" uri="http://test.tag.custom/jsp/impl/taglib"%>
<html>
    <head>
        <meta http-equiv="Content-Type" 
            content="text/html; charset=UTF-8"/>
        <title>EL Math Practice</title>
        <style>
            .err_msg_class {
                color: #AE4386;
                font-size: 22px;
            }
        </style>
        <script type="text/javascript">
            function onErrClick (msg) {
                // hide the message after clicked
                msg.style.display = 'none';
            }
        </script>
    </head>
    <body>
        <!-- Use default style and action -->
        <ct:errMsg msg="Error" msgDescription="This is test error message" />
        <!-- Use custom style and action -->
        <ct:errMsg msg="Error" styleClass="err_msg_class" onClick="onErrClick(this);" />
    </body>
</html>


The result

Test page:



Click on default errMsg (the red one):



Click on customized errMsg:




Reference:
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags.html

Download:

The full project is at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/CustomTagPractice

Wednesday, June 6, 2012

ZK Quick Start


This post is the Quick Start guide of ZK, talking about how to getting it started quickly, NO ZK Studio, NO Maven, just the simple clear traditional way.

1. Download Eclipse:
1.1: Go to Eclipse official site (http://www.eclipse.org/, for 2012-06-06)
1.2: Click Downloads

1.3: Click Eclipse IDE for Java EE Developers (I choose 32 Bit version)

1.4: Click download button to download it.


2. Download Tomcat:
2.1: Go to Tomcat official site (http://tomcat.apache.org/, for 2012-06-06)
2.2: Click 'Tomcat 7.0'

2.3: Find the 'Binary Distributions' and download it

3. Download ZK
3.1: Go to ZK official site (http://www.zkoss.org/, for 2012-06-06)
3.2: Click Downloads -> ZK

3.3: Click 'Download ZK CE' to download it


4. Start Eclipse:
4.1: Extract the downloaded file eclipse-jee-indigo-SR2-win32.zip

4.2: Create a workspace folder for Eclipse

4.3: Double-click on eclipse/eclipse.exe to open it, choose the workspace then click 'OK'

4.4: Click 'Workbench' to enter workbench

5. Add Tomcat Server in Eclipse
5.1: Extract the downloaded file apache-tomcat-7.0.27-windows-x86.zip

5.2: Right-click in Eclipse's Servers view -> New -> Server

5.3: Select Apache/Tomcat v7.0 Server, click next

5.4: Choose server folder, click finish

6. Create Test Project
6.1: Click File -> New -> Dynamic Web Project

6.2: Enter Project name then click Finish

6.3: Extract the downloaded file zk-bin-6.0.1.zip

6.4: Copy all jar files under zk-bin-6.0.1\dist\lib to WebContent/WEB-INF/lib
6.5: Copy zk-bin-6.0.1\dist\WEB-INF\web.xml to WebContent/WEB-INF/

6.6: Right-click on WebContent -> New -> File, create a file 'index.zul' under WebContent

6.7: Edit index.zul as below:

7. Run Test Project
7.1: Right-click on server, click Add and Remove

7.2: Select test project, click Add then click Finish

7.3: Click 'Run' button

7.4: Open browser then go to the test project

7.6: Click the test button, a label will appear


Finish

Sunday, May 20, 2012

Crawl a Site after Login


Introduction

This post is about how to handle cookie and post request to login and crawl some private content.

Prerequest

The LoginCrawler is based on SimpleCrawler, please check it first
http://ben-bai.blogspot.com/2012/04/java-simple-web-crawler.html

About the form post

Assume a form in a page as follows
<form>
<input name="userName" />
<input name="passWord" />
<form>

your user name is 'someone' and password is '123', to post request to login,
the parameters is "userName=someone&passWord=123".

Please note the flow of different site may different, the LoginCrawler is just tested with MediaWiki system.

The Program

LoginCrawler
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/Practice/JAVA/Net/src/test/LoginCrawler.java

Download
SimpleCrawler
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/Practice/JAVA/Net/src/test/SimpleCrawler.java

LoginCrawler
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/Practice/JAVA/Net/src/test/LoginCrawler.java

Reference
http://docs.oracle.com/javase/1.5.0/docs/guide/deployment/deployment-guide/cookie_support.html