Thursday, October 11, 2012

Use Embedded Jetty to Create 'Executable' Web App


Introduction

From Official Site:
Jetty provides an HTTP server, HTTP client, and javax.servlet container. These components are open source and available for commercial use and distribution.

Jetty is used in a wide variety of projects and products. Jetty can be embedded in devices, tools, frameworks, application servers, and clusters. See the Jetty Powered page for more uses of Jetty.

----

This post will talking about how to use embedded jetty to create an 'executable' web app --
double click on a batch file,
then the server started,
and then the browser is opened to a web page in that web app

You can find the binary distribution from official site (http://dist.codehaus.org/jetty/), all required jars are in it.

The Program

JettyClass.java

Config a jetty server and start it

package jetty;


import org.mortbay.jetty.Server;
import org.mortbay.jetty.webapp.WebAppContext;

/**
 * start an embedded jetty server
 *
 */
public class JettyClass {
    public static void main(String[] args) throws Exception {
        // use 8080 port
        Server server = new Server(8080);

        WebAppContext context = new WebAppContext();

        // use relative path, start from project root
        context.setResourceBase("src/webapp/content");
        // page address: http://localhost:8080/EmbeddingJettyTest
        context.setContextPath("/EmbeddingJettyTest");
        context.setParentLoaderPriority(true);

        server.setHandler(context);

        server.start();
        server.join();
    }
}


TestListener.java

Just print some message when server startup to make sure web.xml works fine

package test;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
 * print message when server start,
 * to make sure web.xml works fine
 *
 */
public class TestListener implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println("contextInitialized");
    }

}


web.xml

Define the TestListener in it

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <!-- add a listener to make sure this config file works -->
    <listener>
        <listener-class>test.TestListener</listener-class>
    </listener>
</web-app>


index.jsp

Use some scriptlet to output some message to make sure jsp works fine

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
    <head>
        <meta http-equiv="Content-Type"
            content="text/html; charset=UTF-8">
    </head>
    <body>
        <!-- write some scriptlet to make sure jsp works -->
        <% String msg = "Hello World"; %>
        <%= msg %>
    </body>
</html>


start.bat

Execute the JettyClass and open browser (rem is keyword for comment)

rem /* define library folder */
set lib=.\lib
rem /* folder bin as classpath */
set NEWPATH=bin
rem /* for each *.jar in library folder, append it after classpath */
for %%1 in (%lib%\*.jar) do call :concat %%1

rem /* start chrome before server start */
start chrome http://localhost:8080/EmbeddingJettyTest/
rem /* Execute JettyClass */
java -Xmx128m -classpath %NEWPATH% jetty.JettyClass
goto :eof

rem /* sub function to append string */
:concat
set NEWPATH=%NEWPATH%;%1
goto :eof


The Result

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

Reference

Embedding Jetty
https://docs.codehaus.org/display/JETTY/Embedding+Jetty

batch file string concatenation
http://stackoverflow.com/questions/2027070/batch-file-string-concatenation

Download

Demo flash
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/demo_src/Server/Jetty/EmbeddedJettyTest.swf

Full project is at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/WebServer/JettyTest

Wednesday, October 10, 2012

Embedding HSQLDB in JAVA Application Project


Introduction

Sometimes we may want to test some simple database operation, or let the database portable within our application. In these cases, we can try to use the embedding hsqldb.

Pre-request

The only required jar is hsqldb.jar, you can get the latest version from official site http://hsqldb.org/.

The Program

Test.java:

Start a hsqldb server, execute some sql and show all data in db.

package test;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;

import org.hsqldb.Server;

public class Test {

    private static Connection _connection = null;
    /**
     * create a writer, log hsqldb server info to a file
     * @param logFileName String, the log file name
     * @param append boolean, true: append new content; false: clear old content 
     * @param autoFlush boolean, true: auto flush; false: not auto flush
     * @return PrintWriter
     * @throws IOException
     */
    private static PrintWriter createLogWriter (String logFileName,
        boolean append, boolean autoFlush)
        throws IOException {
        File f = new File(logFileName);

        // create file if not exists
        if (!f.exists()) {
            String logFilePath = f.getAbsolutePath();

            // create parent folders
            File folder = new File(logFilePath.substring(0, logFilePath.indexOf(logFileName)));
            folder.mkdirs();

            // create file
            f.createNewFile();
        }
        FileWriter fw = new FileWriter(f, append);
        return new PrintWriter(fw, autoFlush);
    }
    /**
     * get a db connection
     * @param driverName
     * @param dbUrl
     * @param userName
     * @param password
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    private static Connection getConnection (String dbUrl,
        String userName, String password)
        throws SQLException, ClassNotFoundException {
        if (_connection == null
            || _connection.isClosed()) {
            // Getting a connection to the newly started database
            Class.forName("org.hsqldb.jdbcDriver");
            // Default user of the HSQLDB is 'sa'
            // with an empty password
            return DriverManager.getConnection(dbUrl
                ,userName , password);
        } else {
            return _connection;
        }
    }
    public static void main(String[] args)
        throws ClassNotFoundException, SQLException, IOException {
        String dbName = "testName";
        String path = "testPath";

        
        PrintWriter logWriter =
            createLogWriter(dbName+"_"+path+".log",
                            true, true);
        // start the hsqldb server
        Server hsqlServer = HSQLDBClass.startServer(dbName, path, logWriter);
        Connection connection =
            getConnection("jdbc:hsqldb:hsql://localhost/"+dbName, "sa", "");
        try {

            Random rand = new Random();
            Statement stmt = connection.createStatement();
            // test several SQL operation
            // create table if not exists
            stmt.execute(
                "CREATE TABLE IF NOT EXISTS testTable ( id BIGINT NOT NULL IDENTITY,"
                + "firstName VARCHAR(32),"
                + "lastName VARCHAR(32));");

            // insert data
            stmt.executeUpdate(
                "INSERT INTO testTable (firstName, lastName) VALUES("
                + "'firstName_"+rand.nextInt()+"', 'lastName_"+rand.nextInt()+"')", Statement.RETURN_GENERATED_KEYS);

            // query data
            ResultSet rs = stmt.executeQuery(
                "select * from testTable;");

            while (rs.next()) {
                // show all data
                System.out.println(rs.getBigDecimal(1) + "\t"
                    + rs.getString(2) + "\t"
                    + rs.getString(3) + "\t");
            }
        } finally {
            System.out.println("close connection");
            // Closing the connection
            if (connection != null) {
                connection.close();
            }
            // Stop the server
            if (hsqlServer != null) {
                HSQLDBClass.stopServer(dbName);
            }
        }
    }
}


HSQLDBClass.java

Handle the hsqldb server, start, stop and get instance.

package test;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.hsqldb.Server;

/**
 * A class to handle hsqldb server start/stop and get server instance
 *
 */
public class HSQLDBClass {
    // to store the database server instance
    private static Map<String, Server> _dbMap = new HashMap<String, Server>();
    private static Lock lock = new ReentrantLock();

    /**
     * srart a hsqldb server
     * @param dbName database name
     * @param path the location to store database information
     * @param logWriter where to log hsqldb server log
     * @return Server, a hsqldb Server instance
     */
    public static Server startServer (String dbName, String path, PrintWriter logWriter) {
        lock.lock();
        // 'Server' is a class of HSQLDB representing
        // the database server
        Server hsqlServer = null;
        try {
            if (isServerExist(dbName)) {
                stopServer(dbName);
            } else {
                hsqlServer = new Server();
    
                // The database will be named [dbName]
                // the settings and data of this database
                // will be stored in files
                // [path].properties and [path].script
                hsqlServer.setLogWriter(logWriter);
                hsqlServer.setDatabaseName(0, dbName);
                hsqlServer.setDatabasePath(0, "file:"+path);
    
                // Start the database!
                hsqlServer.start();
                _dbMap.put(dbName, hsqlServer);
            }
        } finally {
            lock.unlock();
        }
        return hsqlServer;
    }
    /**
     * stop a hsqldb server
     * @param dbName String, the key of a hsqldb server
     */
    public static void stopServer (String dbName) {
        lock.lock();
        try {
            Server hsqlServer = _dbMap.get(dbName);
            if (hsqlServer != null) {
                System.out.println("stop server");
                hsqlServer.stop();
                _dbMap.remove(dbName);
            }
        } finally {
            lock.unlock();
        }
    }
    /**
     * get a hsqldb server instance
     * @param dbName String, the key of a hsqldb server
     * @return Server, the hsqldb server instance
     */
    public static Server getServer (String dbName) {
        lock.lock();
        Server hsqlServer = null;
        try {
            hsqlServer = _dbMap.get(dbName);
        } finally {
            lock.unlock();
        }
        return hsqlServer;
    }
    private static boolean isServerExist (String dbName) {
        if (_dbMap.containsKey(dbName))
            return true;
        return false;
    }
}


The Result



Reference

the official document
http://hsqldb.org/doc/2.0/guide/listeners-chapt.html#lsc_app_start


Download

Full project at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/DBPractice/HSQLDB/EmbeddingHSQLDB

Tuesday, October 2, 2012

C++ Type Casting


Introduction

There are 4 specific casting operators in C++, this post is a simple note with respect to implicit conversion, explicit conversion and the 4 specific casting operators.

The Program

type_casting.cpp

/*
 * tested with Dev-C++ 4.9.9.2
 */
#include <iostream>
#include "type_casting.h"

using namespace std;

int main () {
    Base baseInstance;
    Extended extendedInstance;
    Unrelated unrelatedInstance;
    const char* strOne = "text one";

    testImplicitConversion(baseInstance, extendedInstance);
    testExplicitConversion(baseInstance, extendedInstance, unrelatedInstance);
    testDynamicCast(baseInstance, extendedInstance, unrelatedInstance);
    testStaticCast(baseInstance, extendedInstance, unrelatedInstance);
    testReinterpretCast(baseInstance, extendedInstance, unrelatedInstance);
    testConstCast(const_cast<char *>(strOne));

    
    system("PAUSE");
}

/**
 **** **** Implicit conversions **** ****
 * do not require any operator
 * they are automatically performed when a value is
 * copied to a compatible type.
 */
void testImplicitConversion(Base baseInstance, Extended extendedInstance) {
    // correct, sub class to super class
    Base b = extendedInstance;
    cout << "test implicit conversions" << endl;
    cout << b.a << endl << endl;
    // wrong, no 'b' in Base class
    // cout << b.b << endl

    // wrong, super class to sub class
    // Extended e = baseInstance;
}

/**
 **** **** Explicit conversion **** ****
 * for most needs with fundamental data types
 * can be applied indiscriminately on classes and pointers to classes,
 * which can * lead to code that while being syntactically correct
 * can cause runtime errors
 */

void testExplicitConversion (Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance) {
    // correct, sub class to super class
    Base b = (Base)extendedInstance;
    cout << "test explicit conversion" << endl;
    cout << b.a << endl << endl;
    // wrong, no 'b' in Base class
    // cout << b.b << endl

    // syntactically correct, super class pointer to sub class pointer
    Extended *pe = (Extended*)&baseInstance;
    // runtime error, no 'b' in Base class
    // cout << pe->b << endl;

    // wrong, Unrelated to Base
    // Base *pb = (Unrelated*)&unrelatedInstance;
}

/**
 **** **** dynamic_cast **** ****
 *
 * can be used only with pointers and references to objects.
 *
 * Its purpose is to ensure that the result of the type conversion
 * is a valid complete object of the requested class.
 *
 * has overhead of the type-safety checks at run time
 */
void testDynamicCast(Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance) {
    cout << "test dynamic cast" << endl;
    // correct, cast sub class pointer to super class pointer
    Base* pb = dynamic_cast<Base*>(&extendedInstance);
    Extended* pe;

    // output: 1
    cout << pb->a << endl << endl;
    
    // wrong, cast between two unrelated class pointer
    // pb = dynamic_cast<Base*>(&unrelatedInstance);

    // wrong, cast super class pointer to sub class pointer
    // pe = dynamic_cast<Extended*>(&baseInstance);

}

/**
 **** **** static_cast **** ****
 *
 * can perform conversions between pointers to related classes,
 * can also be used to perform any other non-pointer conversion that
 * could also be performed implicitly,
 * or any conversion between classes with explicit constructors or
 * operator functions as described in "implicit conversions" above.
 *
 * ensures that at least the classes are compatible if the proper
 * object is converted, but no safety check is performed during runtime
 * to check if the object being converted is in fact a full object of
 * the destination type
 *
 * the overhead of the type-safety checks of dynamic_cast is avoided
 */
void testStaticCast(Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance) {
    cout << "test static cast" << endl;
    // correct, cast sub class pointer to super class pointer
    Base* pb = static_cast<Base*>(&extendedInstance);
    // output: 1
    cout << pb->a << endl;
    // wrong, no 'b' in Base
    // cout << pb->b << endl;

    // correct, cast super class pointer to sub class pointer
    Extended* pe = static_cast<Extended*>(&baseInstance);
    // output: 1
    cout << pe->a << endl << endl;
    // wrong, there is 'b' in Extended but the real object that pe points to is a Base object
    // can run it but the value is unexpectable
    // cout << pe->b << endl;

    // wrong, cast between unrelated class
    // pe = static_cast<Extended*>(&unrelatedInstance);

    // correct, valid Implicit conversion -> valid static_cast
    Base biTwo = static_cast<Base>(extendedInstance);
    // wrong, invalid Implicit conversion -> invalid static_cast
    // Extended eiTwo = static_cast<Extended>(baseInstance);
}
/**
 **** **** reinterpret_cast **** ****
 * converts any pointer type to any other pointer type
 *
 * can also cast pointers to or from integer types
 */
void testReinterpretCast(Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance) {
    cout << "test reinterpret cast" << endl;
    // cast between unrelated class
    Extended* pe = reinterpret_cast<Extended*>(&unrelatedInstance);
    // maybe unsafe
    cout << pe->a << endl << pe->b << endl;

    // cast pointer to integer
    int nptr = reinterpret_cast<int>(&unrelatedInstance);
    cout << nptr << endl;
    // cast int to pointer
    Base *pb = reinterpret_cast<Base*>(nptr);
    cout << pb->a << endl << endl;
}

/**
 **** **** const_cast **** ****
 * manipulates the constness of an object, either to be set or to be removed
 */
void testConstCast (char* strOne) {
    cout << "test const cast" << endl;
    cout << strOne << endl << endl;
}


type_casting.h

class Base {
    public:
        int a;
        Base ()
        {
            a = 1;
        }
};
class Extended : public Base {
    public:
        float b;
        Extended ()
        {
            b = 2.2;
        }
};
class Unrelated {
    public:
        int c;
        float d;
        Unrelated ()
        {
            c = 3;
            d = 4.4;
        }
};
void testImplicitConversion(Base baseInstance, Extended extendedInstance);
void testExplicitConversion (Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance);
void testDynamicCast(Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance);
void testStaticCast(Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance);
void testReinterpretCast(Base baseInstance, Extended extendedInstance, Unrelated unrelatedInstance);
void testConstCast (char* strOne);


Reference

http://www.cplusplus.com/doc/tutorial/typecasting/


Download

files at github
https://github.com/benbai123/C_Cplusplus_Practice/tree/master/CPP/CPP_Basic/CPP_Type_casting

Wednesday, September 26, 2012

C++ Class Extend and Member Scope



Introduction

A simple practice of C++ class extend and member scope:

public member can be accessed by any object
protected member can be accessed by self and sub classes
private member can be accessed by self only

Test Sample

BaseClass.h

class BaseClass {
    // sub class and any other object can access public member directly
    public: 
        int _varOne; // public member field
        BaseClass()
        {
            _varOne = 0;
            _varTwo = 0;
            _varThree = 0;       
        }
        // where _varOne(varOne) denotes assign varOne to _varOne
        BaseClass (int varOne, int varTwo, int varThree) : _varOne(varOne),
                _varTwo(varTwo), _varThree(varThree)
        {
        }
        int getVarOne ()
        {
            return _varOne;
        }
        int getVarTwo ()
        {
            return _varTwo;
        }
        int getVarThree ()
        {
            return _varThree;
        }
    // sub class can access protected member directly
    // any other object cannot access protected member directly
    protected:
        int _varTwo; // protected member field
    // sub class and any other object cannot access private member directly
    private:
        int _varThree; // private member field
}; 


ExtendedClass.h


#include <iostream>
#include "BaseClass.h"

using namespace std;

/** Extends BaseClass
 * then can access all public/protected member of
 * BaseClass directly in ExtendedClass
 */
class ExtendedClass : public BaseClass {
    public:
        ExtendedClass ()
        {
            // will call super class' basic constructor
            _varFour = 0;
        }
        // call constructor in super class
        ExtendedClass (int varOne, int varTwo, int varThree, int varFour) : BaseClass (varOne, varTwo, varThree),
                _varFour(varFour) // then assign value
        {
        }
        int getVarFour ()
        {
            return _varFour;
        }
        void showAll ()
        {
            cout << "\tvarOne: " << _varOne << endl // _varOne is public
                << "\tvarTwo: " << _varTwo << endl // _varTwo is protected
                << "\tvarThree: " << getVarThree() << endl // _varThree is private member in super class

            // Error! cannot access super class' private member
            // <<"varThree: " << _varThree << endl

                << "\tvarFour: " << _varFour << endl << endl; // _varFour is in this class
        }
    private:
        int _varFour;
};


test.cpp


#include <iostream>
#include "ExtendedClass.h"

using namespace std;

int main() {
    ExtendedClass e1;
    ExtendedClass e2(1, 2, 3, 4);

    cout << "\te2._varOne: " << e2._varOne << endl << endl;
    cout << "\te2._varTwo: " << e2.getVarTwo() << endl << endl;
    cout << "\te2._varThree: " << e2.getVarThree() << endl << endl;
    cout << "\te2._varFour: " << e2.getVarFour() << endl << endl;


    // Error! _varTwo is protected member in e2's super class
    // can only access it directly in BaseClass or ExtendedClass
    // cout << "e2._varTwo: " << e2._varTwo << endl << endl;

    // Error! _varThree is private member in e2's super class
    // cout << "e2._varThree: " << e2._varThree << endl << endl;

    // Error! _varFour is private member in e2's class
    // cout << "e2._varFour: " << e2._varFour << endl << endl;

    e1.showAll();
    e2.showAll();
    system("PAUSE");
}


The Result




Reference

http://www.cplusplus.com/doc/tutorial/inheritance/


Download

Files at github
https://github.com/benbai123/C_Cplusplus_Practice/tree/master/CPP/CPP_Basic/CPP_Extend_and_scope

Monday, September 17, 2012

C/C++ escape characters and operator order

Simple note

escape characters

\a: alert bell
\b: backspace
\f: formfeed
\n: newline
\r: return
\t: horizontal tab
\v: vertical tab
\\: backslash
\?: question mark
\': single quote
\": double quote

operator order
1    ::     Scope resolution     Left-to-right
2    ++   --     Suffix/postfix increment and decrement
    ()     Function call
    []     Array subscripting
    .     Element selection by reference
    ?>     Element selection through pointer
3    ++   --     Prefix increment and decrement     Right-to-left
    +   ?     Unary plus and minus
    !   ~     Logical NOT and bitwise NOT
    (type)     Type cast
    *     Indirection (dereference)
    &     Address-of
    sizeof     Size-of
    new, new[]     Dynamic memory allocation
    delete, delete[]     Dynamic memory deallocation
4    .*   ->*     Pointer to member     Left-to-right
5    *   /   %     Multiplication, division, and remainder
6    +   ?     Addition and subtraction
7    <<   >>     Bitwise left shift and right shift
8    <   <=     For relational operators < and ? respectively
    >   >=     For relational operators > and ? respectively
9    ==   !=     For relational = and ≠ respectively
10    &     Bitwise AND
11    ^     Bitwise XOR (exclusive or)
12    |     Bitwise OR (inclusive or)
13    &&     Logical AND
14    ||     Logical OR
15    ?:     Ternary conditional     Right-to-left
    =     Direct assignment (provided by default for C++ classes)
    +=   ?=     Assignment by sum and difference
    *=   /=   %=     Assignment by product, quotient, and remainder
    <<=   >>=     Assignment by bitwise left shift and right shift
    &=   ^=   |=     Assignment by bitwise AND, XOR, and OR
16    throw     Throw operator (for exceptions)
17    ,     Comma     Left-to-right


Reference

http://www.developerz.com/cplusplus_escapesequences.htm
http://en.cppreference.com/w/cpp/language/operator_precedence

Sunday, September 16, 2012

Use Google Places Autocomplete with ZK Gmaps


Introduction

Places Autocomplete

From Google Maps JavaScript API v3 Reference:


The Places Autocomplete feature attaches to a text field on your web page, and monitors that field for character entries. As text is entered, Autocomplete returns Place predictions to the application in the form of a drop-down pick list.

When a user selects a Place from the list, information about the Place is returned to the Autocomplete object, and can be retrieved by your application.


ZK Gmaps

From ZK Component Reference:

A gmaps is a maps component that wraps the famous Google Maps service that you can control it and embedded it in your ZK web application page in pure Java.



This post is about how to use Google Maps Places Autocomplete with ZK Gmaps.

The Program

geo_autocomplete_test.zul

<zk xmlns:w="client">
    <!-- 
        Tested with ZK 6.0.2 and ZK-Gmaps 3.0.1
     -->
    <script type="text/javascript"><![CDATA[
        function init (wgt) {
            var loadAPI = setInterval(function() {
                // wait until places library ready
                if (window.google && window.google.maps && window.google.maps.places) {
                    var maps = google.maps,
                        complete = wgt._autocomplete = new google.maps.places.Autocomplete(wgt.getInputNode());

                    // listen to google's place_changed event
                    wgt._placeChanged = google.maps.event.addListener(wgt._autocomplete, 'place_changed', function () {
                        var p = complete.getPlace();
                        // triggered wrong
                        if (!p || !p.geometry)
                            return;
                        // prepare event data
                        var node = jq(wgt.getInputNode()),
                            location = p.geometry.location,
                            data = {place: p,
                                    lat: location.lat(),
                                    lng: location.lng()};
                        // fire onPlaceChanged event to CustomTextbox
                        wgt.fire('onPlaceChanged', data);
                    });
                    clearInterval(loadAPI);
                }
            }, 100);
        }
    ]]></script>
    <!-- This textbox uses the CustomTextbox which
        listen to onPlaceChanged event to receive the
        lat/lng from Google Maps Places Autocomplete
     -->
    <div style="margin: 20px;">
        <textbox use="test.geo.autocomplete.CustomTextbox">
            <attribute w:name="bind_"><![CDATA[
                function (a, b, c) {
                    // call original bind_ function
                    this.$bind_(a, b, c);
                    // attach to geo-autocomplete
                    init (this);
                }        
            ]]></attribute>
            <attribute name="onPlaceChanged"><![CDATA[
                import test.geo.autocomplete.PlaceChangedEvent;
                PlaceChangedEvent evt = (PlaceChangedEvent)event;
                gmap.setLat(evt.getLat());
                gmap.setLng(evt.getLng());
            ]]></attribute>
        </textbox>
        <!-- load Google Maps Places library
            by gmaps
         -->
        <gmaps id="gmap" width="500px" height="500px"
            libraries="geometry,places" />
    </div>
</zk>


We create a textbox with CustomTextbox class and use the input node of textbox to create google.maps.places.Autocomplete, fire onPlaceChanged event as need.

CustomTextbox.java

package test.geo.autocomplete;

import java.util.Map;

import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Textbox;
/**
 * Tested with ZK 6.0.2 and ZK-Gmaps 3.0.1
 */
public class CustomTextbox extends Textbox {
    // listen to onPlaceChanged event with specific config
    static {
        addClientEvent(CustomTextbox.class, "onPlaceChanged",
                CE_IMPORTANT|CE_DUPLICATE_IGNORE);
    }
    public void service(org.zkoss.zk.au.AuRequest request, boolean everError) {
        final String cmd = request.getCommand();
        // handle event if it is onPlaceChanged event
        if ("onPlaceChanged".equals(cmd)) {
            // get data
            final Map data = request.getData();
            double lat = ((Double) data.get("lat")).doubleValue();
            double lng = ((Double) data.get("lng")).doubleValue();
            // create and post event
            PlaceChangedEvent evt = new PlaceChangedEvent(cmd, lat, lng);
            // post event to the custom textbox
            Events.postEvent(this, evt);
        } else {
            super.service(request, everError);
        }
    }
}


The CustomTextbox listen to onPlaceChanged event and post PlaceChangedEvent event as need.

PlaceChangedEvent.java


package test.geo.autocomplete;

import org.zkoss.zk.ui.event.Event;

/**
 * Tested with ZK 6.0.2 and ZK-Gmaps 3.0.1
 */
public class PlaceChangedEvent extends Event {

    private static final long serialVersionUID = 7538146314204639298L;
    double _lat;
    double _lng;
    public PlaceChangedEvent(String name, double lat, double lng) {
        super(name);
        _lat = lat;
        _lng = lng;
    }
    public Double getLat () {
        return _lat;
    }
    public Double getLng () {
        return _lng;
    }
}

Use this event to store the lat/lng info.

The Result
View demo on line
http://screencast.com/t/GtsCMZ4JiNeD


Reference
https://developers.google.com/maps/documentation/javascript/places


Download

Demo flash at github
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/addon/GEOAutocomplete.swf

Full project at github
https://github.com/benbai123/ZK_Practice/tree/master/Components/projects/Addon_Practice/GmapsPractice

Sunday, September 9, 2012

ZK: Adding abort button to busy mask



Introduction

In ZK, we can use a mask to prevent any action during a long operation, sometimes we may want to provide 'abort' function to terminate the long operation.

In this case, we can use Client Side Programming to add some widget (with respect to the abort function) into the mask instead of recreating or custommizing the UI completely.

This post will show how to add an abort button into the 'busy' mask to provide the 'abort' function to terminate a long operation.

The Program

adding_abort_button_to_busy_mask.zul

<zk>
    <script type="text/javascript"><![CDATA[
        function showBusy () {
            // show busy mask
            zAu.cmd0.showBusy('Loading...');
            // move abort button under busy message
            jq('.z-loading')[0].appendChild(jq('$abortButton')[0]);
        }
        function clearBusy () {
            // move abort button back under abort div
            jq('$abortDiv')[0].appendChild(jq('$abortButton')[0]);
            // clear busy mask
            zAu.cmd0.clearBusy(null);
        }
    ]]></script>
    <zscript><![CDATA[
        /** A class that implement Runnable to do
         * the long operation
         */
        class AbortableRunnable implements Runnable {
            boolean stopped = true;
            int i = 0;
            public void run () {
                stopped = false;
                while (true) {
                    // do somoething
                    i++;
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        System.out.println(e);
                    }
                    // finish or aborted
                    if (i == 5 || stopped)
                        break;
                }
            }
            public void abort () {
                stopped = true;
            }
            public boolean isRunning () {
                return !stopped;
            }
            public int getI () {
                return i;
            }
        }
        AbortableRunnable ar = new AbortableRunnable();
        
        void start () {
            // start thread
            new Thread(ar).start();
        }
        void abort () {
            // update status
            status.setValue("aborted i = " + ar.getI());
            // stop thread
            ar.abort();
            // reset
            ar = new AbortableRunnable();
        }
        void finish () {
            // update status
            status.setValue("finished i = " + ar.getI());
            // reset
            ar = new AbortableRunnable();
        }
    ]]></zscript>
    <!-- abort div to keep the abort button,
        display outside the screen -->
    <div id="abortDiv" style="position: absolute; left: -1000px;">
        <!-- abort button stop the running thread any time
            and clear busy mask -->
        <button id="abortButton" label="abort">
            <attribute name="onClick">
                // abort the running process
                abort();
                // stop the checking timer
                checkTimer.stop();
                // move self element back to abort div
                // and clear the busy mask
                Clients.evalJavaScript("clearBusy();");
            </attribute>
        </button>
    </div>
    <div style="margin: 50px;">
        <!-- start button atart the thread
            and show busy mask -->
        <button label="do something long">
            <attribute name="onClick">
                // start to run the process
                start();
                // start the checking timer
                checkTimer.start();
                // show busy mask and move
                // the element of abort button under busy message
                Clients.evalJavaScript("showBusy();");
            </attribute>
        </button>
        <!-- checking timer clear busy mask after thread finished successfully -->
        <timer id="checkTimer" running="false" repeats="true" delay="100">
            <attribute name="onTimer">
                if (ar.isRunning()) // update status if is running
                    status.setValue("running... i = " + ar.getI());
                if (ar.getI() == 5) { // finish condition
                    finish();
                    // stop self
                    self.stop();
                    // move self element back to abort div
                    // and clear the busy mask
                    Clients.evalJavaScript("clearBusy();");
                }
            </attribute>
        </timer>
        Status: <label id="status" value="" />
    </div>
</zk>


The Result

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

Reference
http://ben-bai.blogspot.tw/2012/07/introduction-sometimes-we-may-need-to.html

Download

Source code at github
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/WebContent/adding_abort_button_to_busy_mask.zul

Demo flash at github
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/adding_abort_button_to_busy_mask.swf