low level programmer

Main | Next page »
星期五 一月 29, 2010

counting sort

description

覺得如果不是寫程式的話, counting sort 還蠻難想像的.
照自己以為的 counting sort 寫出來, 如果有錯請指導了謝謝.

reference

這是 wiki 上的說明以及 C 的實作.

codes


package test;

public class TestCountingSort {

    /**
     * @param target is the unsorted number array
     */
    public static void countingSort(int[] target) {
        // find max and min
        int max = 0;
        int min = 0;
        for (int num : target) {
            if ( num > max ) {
                max = num;
            }
            if ( num < min ) {
                min = num;
            }
        }
        // add one into counter which index is the sorting number
        int zeroOffset = 0 - min;
        int counterSize = max + zeroOffset + 1;
        int[] counter = new int[counterSize];
        for (int num : target) {
            counter[num + zeroOffset]++;
        }
        // put result from counter into target array
        for ( int targetIdx = 0; targetIdx < target.length; targetIdx++ ) {
            for ( int counterIdx = min + zeroOffset; counterIdx < counterSize; counterIdx++ ) {
                if ( counter[counterIdx] > 0 ) {
                    target[targetIdx] = counterIdx - zeroOffset;
                    counter[counterIdx]--;
                    break;
                }
            }            
        }
        // show result
        for (int num : target) {
            System.out.print(num + ", ");
        }
    }

    public static void main(String[] args) {
        countingSort(new int[]{-1,84,13,0,0,73,26,32,19,91,38});
    }
    
}

星期六 九月 19, 2009

指定 package iterate 包含 jar 檔內所有 sub package 的 class

以前就好奇現在很多工具只要 annotation 就可以紀錄你有哪些 class 是註冊要做某事的行為怎麼實做.
也就是好奇要怎麼 iterate 所有的 class 進行操作呢?
今天看到 stripes 的 ResolverUtil.java 就有這種行為.
感覺像是這樣.

package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class TestIterateClasses {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        TestIterateClasses test = new TestIterateClasses();
        // 這裡指定的 package 不管是 source code 或 library 下的都可以把所有 class 顯示出來
        test.test("org.apache.commons.pool.impl");
    }
    
    private void test(String javaPackageName) throws IOException {
        String packageName = javaPackageName.replaceAll("\\.", "/");
        // 這裡可以找到有指定 package 的 library 有哪些
        Enumeration urls = Thread.currentThread().getContextClassLoader().getResources(packageName);
        while (urls.hasMoreElements()) {
            String urlPath = urls.nextElement().getFile();
            if ( urlPath.startsWith("file:") ) {
                urlPath = urlPath.substring(5);
            }
            if ( urlPath.indexOf("!") > 0 ) {
                urlPath = urlPath.substring(0, urlPath.indexOf("!"));
            }
            File file = new File(urlPath);
            if ( file.isDirectory() ) {
                iterateDirectory( packageName, file );
            } else {
                showClassInJarFile( file, packageName );
            }

        }        
    }

    private void showClassInJarFile(File file, String packageName) throws IOException {
        JarInputStream jarIs = new JarInputStream(new FileInputStream(file));
        JarEntry entry = null;
        while ( (entry = jarIs.getNextJarEntry()) != null ) {
            // 還不確定這有沒有更快的方式, 不然其實是 iterate 所有的 package
            if ( entry.getName().endsWith(".class") 
                    && entry.getName().indexOf(packageName) > -1 ) {
                System.out.println(entry.getName());
            }
        }
    }

    private void iterateDirectory(String packageName, File directory) throws IOException {
        File[] files = directory.listFiles();
        for (File file : files) {
            System.out.println("iterate directory:" + packageName + "/" + file.getName());
            if ( file.isDirectory() ) {
                iterateDirectory( packageName, file );
            } else {
                showClassInFileDirectory( file );
            }
        }
    }

    private void showClassInFileDirectory(File file) {
        if ( file.getName().endsWith(".class") ) {
            System.out.println(file);
        }
    }
}

星期日 九月 13, 2009

做 immutable class 時讓 List 真的不能被改變

上次看到一篇文章寫得很不錯, 但是忘記網址了,
反正就是在說實做 immutable 要注意的地方.
今天剛好需要 immutable class, 有個 List 的變數, 我想讓它 immutable
這時候就是用 Collections#unmodifiableList,
要注意雖然 unmodifiableList 會產生一個不能 modify 的 List.
但傳進去的 List instance 卻還是可以被編輯, 所以仍然可以透過操作傳進去的物件改變內容, 這樣就不是 immutable 了.
所以要做 immutable 的 List 除了呼叫 unmodifiableList 以外還要用 ArrayList 包起來


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestCollections {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<String>();
        stringList.add("A");
        stringList.add("B");
        stringList.add("C");

        List<String> notReallyUnmodifiedList = Collections.unmodifiableList( stringList );
        stringList.add("D");
        
        try {
            notReallyUnmodifiedList.add("Trigger exception");
        } catch (Exception ex) {
            System.out.println("Yes! You can't modify notReallyUnmodifiedList directly");
        }

        // will print ABCD
        System.out.print("notReallyUnmodifiedList=");
        for (String str : notReallyUnmodifiedList) {
            System.out.print(str);
        }
        System.out.println();

        List<String> reallyUnmodifiedList = Collections.unmodifiableList( new ArrayList<String>(stringList) );
        stringList.add("E");

        try {
            reallyUnmodifiedList.add("Trigger exception");
        } catch (Exception ex) {
            System.out.println("Yes! You can't modify reallyUnmodifiedList directly");
        }

        // will print ABCD, not ABCDE
        System.out.print("reallyUnmodifiedList=");
        for (String str : reallyUnmodifiedList) {
            System.out.print(str);
        }
        System.out.println();
    }
}

星期五 七月 24, 2009

Study effective java 2nd note - 如果建構子的參數很多怎麼辦

如果有一個建構子的參數超過四個, 而且很多是 optional 的.
可用 Builder 建立參數物件.
參考作法是一個 immutable 的參數物件加上一個 mutable 的 inner builder class.
透過對 inner class 的呼叫設定想要的參數值後呼叫 build 建立一個 immutable 的參數物件.


package test;

import org.apache.commons.lang.builder.ToStringBuilder;
import test.PersonalInfo.PersonalInfoBuilder;


public class TestBuilder {

    public static void main(String[] args) {
        PersonalInfo info = new PersonalInfoBuilder()
                                            .address("myaddress")
                                            .age(5)
                                            .cellphone("1234567890")
                                            .firstName("my first name")
                                            .lastName("my last name")
                                            .phone("myphone")
                                            .build();
        System.out.println(info);
    }
    
}



class PersonalInfo {

    private final String firstName;
    private final String lastName;
    private final int age;
    private final String address;
    private final String phone;
    private final String cellphone;

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }

    public String getPhone() {
        return phone;
    }

    public String getCellphone() {
        return cellphone;
    }

    public static class PersonalInfoBuilder implements Builder<PersonalInfo> {
        private String firstName = "";
        private String lastName = "";
        private int age = 0;
        private String address = "";
        private String phone = "";
        private String cellphone = "";

        public PersonalInfoBuilder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public PersonalInfoBuilder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public PersonalInfoBuilder age(int age) {
            this.age = age;
            return this;
        }

        public PersonalInfoBuilder address(String address) {
            this.address = address;
            return this;
        }

        public PersonalInfoBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public PersonalInfoBuilder cellphone(String cellphone) {
            this.cellphone = cellphone;
            return this;
        }

        @Override
        public PersonalInfo build() {
            return new PersonalInfo( this );
        }
    }

    private PersonalInfo(PersonalInfoBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.address = builder.address;
        this.phone = builder.phone;
        this.cellphone = builder.cellphone;
    }

}
interface Builder<T> {
    T build();
}

星期日 七月 12, 2009

double-checked locking 在JDK5後搭配 volatile 可實做 singleton

最近才知道原來 double-checked locking 其實是不能實作 singleton 的.
一開始看不太懂為什麼, 後來上網查之後才知道原因.
不過以前看書的時候有說到 double-checked locking 在 JDK5 之後能用.
那時候還不知道為什麼, 現在才知道...原來如此...

The "Double-Checked Locking is Broken" Declaration

星期一 六月 15, 2009

Try Lucene and Perf4j

description

最近看一下 Lucene, 記錄一下最簡單的用法.
這裡是把 source code 搬進 testlucene/doc 中做 index 再搜尋看找的字出現在哪幾個檔案
另外因為全文檢索都會有幾秒做完什麼, 剛好跟 Perf4j 的目的一樣, 所以一起用用看.

reference

Lucene
Perf4j

codes


package test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.demo.FileDocument;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.perf4j.StopWatch;
import org.perf4j.log4j.Log4JStopWatch;

public class TestMain {

    private static final Logger logger = Logger.getLogger(TestMain.class);
    private static final StopWatch profiler = new Log4JStopWatch(logger);

    public static void main(String[] args) {
        try {
            TestMain test = new TestMain();
            profiler.start(TestMain.class.getName());
            test.testIndex();
            profiler.stop(TestMain.class.getName(), "index finished");
            profiler.start(TestMain.class.getName());
            test.testSearch("findWord1 orFindWord2");
            profiler.stop(TestMain.class.getName(), "search finished");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void testSearch(String searchWord) throws Exception {
        IndexReader reader = IndexReader.open(FSDirectory.open(new File("testlucene/index")), true);
        Searcher searcher = new IndexSearcher(reader);
        Analyzer analyzer = new StandardAnalyzer(true, toSet(StandardAnalyzer.STOP_WORDS));
        QueryParser parser = new QueryParser("contents", analyzer);
        Query query = parser.parse(searchWord);
        logger.info("search for " + query.toString(searchWord));

        TopDocs hits = searcher.search(query, 10000);
        for (ScoreDoc scoreDoc : hits.scoreDocs) {
            Document doc = searcher.doc( scoreDoc.doc );
            logger.info("find searched word in path:" + doc.get("path"));
        }
    }


    private void testIndex() throws Exception {
        IndexWriter writer = new IndexWriter(FSDirectory.open(new File("testlucene/index")), new StandardAnalyzer(true, toSet(StandardAnalyzer.STOP_WORDS)), true, new IndexWriter.MaxFieldLength(1000000));
        File docDir = new File("testlucene/doc");
        indexDocs( writer, docDir );
        writer.optimize();
        writer.close();
    }

    private void indexDocs(IndexWriter writer, File file)
            throws IOException {
        // do not try to index files that cannot be read
        if (file.canRead()) {
            if (file.isDirectory()) {
                String[] files = file.list();
                // an IO error could occur
                if (files != null) {
                    for (int i = 0; i < files.length; i++) {
                        indexDocs(writer, new File(file, files[i]));
                    }
                }
            } else {
                logger.info("adding " + file);
                try {
                    writer.addDocument(FileDocument.Document(file));
                } // at least on windows, some temporary files raise this exception with an "access denied" message
                // checking if the file can be read doesn't help
                catch (FileNotFoundException fnfe) {
                    fnfe.printStackTrace();
                }
            }
        }
    }
    

    private Set<String> toSet(String[] words) {
        if ( words == null ) { return new HashSet<String>(); }
        Set<String> result = new HashSet<String>();
        for (String word : words) {
            result.add( word );
        }
        return result;
    }

}

星期一 六月 08, 2009

JDBC query update util with Connection Pool

description

用 JDBC 的時候, 要從 ResultSet 取出資料放進 java bean 的 getter/setter 很麻煩.
所以寫這個基礎的 query/update 的 class.
如果可以把 SQL 更精簡就好了, 但目前還沒想到怎麼做.

reference

commons-dbcp
commons-beanutils
commons-collections
commons-lang
commons-logging
commons-pool
log4j

codes

/**
 * All methods will exceptionIfNotWorking before do their job, besides method start will call exceptionIfWorking<br>
 * exceptionIfWorking and exceptionIfNotWorking will throw IllegalStateException if the state is wrong.
 */
public class DBCenter {

    private static boolean working = false;
    private static final Logger logger = Logger.getLogger(DBCenter.class);
    private static BasicDataSource dataSource;

    private DBCenter() {
    }

    public static void start(DBCenterConf confProp) {
        exceptionIfWorking();
        dataSource = new BasicDataSource();
        dataSource.setDriverClassName(confProp.getDriver());
        dataSource.setUsername(confProp.getUsername());
        dataSource.setPassword(confProp.getPassword());
        dataSource.setUrl(confProp.getDbUrl());
        dataSource.setMaxActive(confProp.getMaxActive());
        dataSource.setMaxIdle(confProp.getMaxIdle());
        dataSource.setMaxWait(confProp.getMaxWait());
        working = true;
        if (logger.isInfoEnabled()) {
            logger.info("Start up DBCP success.");
            logger.info("driver=" + dataSource.getDriverClassName());
            logger.info("username=" + dataSource.getUsername());
            logger.info("max.active=" + dataSource.getMaxActive());
            logger.info("max.idle=" + dataSource.getMaxIdle());
            logger.info("max.wait=" + dataSource.getMaxWait());
        }
    }

    public static void stop() {
        try {
            if (dataSource != null) {
                dataSource.close();
                logger.info("Stop DBCP successfully.");
            }
        } catch (Exception ex) {
            logger.error("Stop datasource fail.", ex);
        } finally {
            dataSource = null;
            working = false;
        }
    }

    /** @throws IllegalStateException if is working */
    private static void exceptionIfWorking() {
        if (working) {
            throw new IllegalStateException("DataSource is not working!");
        }
    }

    /** @throws IllegalStateException if is not working */
    private static void exceptionIfNotWorking() {
        if (!working) {
            throw new IllegalStateException("DataSource is not working!");
        }
    }

    /**
     * @see PreparedStatement#executeUpdate() 
     */
    public static int update(String sql, Object... params) {
        exceptionIfNotWorking();
        logger.info("[sqlCmd] " + sql);
        int updateRows = 0;
        params = params == null ? new Object[0] : params;
        try {
            Connection conn = getConnection();
            PreparedStatement pstmt = conn.prepareCall(sql);
            for (int i = 1; i <= params.length; i++) {
                pstmt.setObject(i, params[i - 1]);
            }
            updateRows = pstmt.executeUpdate();
            closeResources(conn, null, pstmt);
        } catch (Exception ex) {
            logger.error("Fail to findAll.", ex);
        }
        return updateRows;
    }

    /**
     * @see PreparedStatement#execute()
     */
    public static void execute(String sql, Object[] params) {
        exceptionIfNotWorking();
        logger.info("[sqlCmd] " + sql);
        params = params == null ? new Object[0] : params;
        try {
            Connection conn = getConnection();
            PreparedStatement pstmt = conn.prepareCall(sql);
            for (int i = 1; i <= params.length; i++) {
                pstmt.setObject(i, params[i - 1]);
            }
            pstmt.execute();
            closeResources(conn, null, pstmt);
        } catch (Exception ex) {
            logger.error("Fail to findAll.", ex);
        }
    }

    public static <T> List<T> query(Class<T> modelCls, String sql, Object[] params) {
        exceptionIfNotWorking();
        logger.info("[sqlCmd] " + sql);
        params = params == null ? new Object[0] : params;
        List<T> result = new ArrayList<T>();
        try {
            Connection conn = getConnection();
            PreparedStatement pstmt = conn.prepareCall(sql);
            for (int i = 1; i <= params.length; i++) {
                pstmt.setObject(i, params[i - 1]);
            }
            ResultSet rs = pstmt.executeQuery();
            result = copy(modelCls, rs);
            closeResources(conn, rs, pstmt);
        } catch (Exception ex) {
            logger.error("Fail to findAll.", ex);
        }
        return result;
    }

    private static <T> List<T> copy(Class<T> cls, ResultSet rs) throws Exception {
        if (cls == null || rs == null) {
            throw new IllegalArgumentException("class and ResultSet can't be null.");
        }
        List<T> result = new ArrayList<T>();
        ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);
        Iterator rows = rsdc.iterator();
        while (rows.hasNext()) {
            DynaBean row = (DynaBean) rows.next();
            T model = copy(cls, row);
            PropertyUtils.copyProperties(model, row);
            result.add(model);
        }
        return result;
    }

    private static <T> T copy(Class<T> cls, DynaBean dynaBean) throws Exception {
        if (cls == null || dynaBean == null) {
            throw new IllegalArgumentException("class and dynabean can't be null");
        }
        T result = cls.newInstance();
        PropertyUtils.copyProperties(result, dynaBean);
        return result;
    }

    private static Connection getConnection() {
        exceptionIfNotWorking();
        Connection result = null;
        try {
            result = dataSource.getConnection();
        } catch (SQLException ex) {
            logger.error("Get connection fail.", ex);
        }
        return result;
    }

    private static void closeResources(Connection conn, ResultSet rs, PreparedStatement pstmt) {
        exceptionIfNotWorking();
        if (rs != null) {
            try {
                rs.close();
            } catch (Exception ex) {
                logger.error("Close ResultSet fail.", ex);
            } finally {
                rs = null;
            }
        }
        if (pstmt != null) {
            try {
                pstmt.close();
            } catch (Exception ex) {
                logger.error("Close PreparedStatement fail.", ex);
            } finally {
                pstmt = null;
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception ex) {
                logger.error("Close connection fail.", ex);
            } finally {
                conn = null;
            }
        }
    }
}

DBCenterConf.java
public class DBCenterConf {

    private static final String KEY_DRIVER = "driver";
    private static final String KEY_USERNAME = "username";
    private static final String KEY_PASSWORD = "password";
    private static final String KEY_DBURL = "dburl";
    private static final String KEY_MAX_ACTIVE = "max.active";
    private static final String KEY_MAX_IDLE = "max.idle";
    private static final String KEY_MAX_WAIT = "max.wait";
    private String driver = "";
    private String username = "";
    private String password = "";
    private String dbUrl = "";
    private int maxActive = 20;
    private int maxIdle = 30;
    private int maxWait = 30;

    public static DBCenterConf newInstance(InputStream in) throws IOException {
        Properties prop = new Properties();
        prop.load(in);
        DBCenterConf result = new DBCenterConf();
        result.setDriver( prop.getProperty(KEY_DRIVER) );
        result.setDbUrl( prop.getProperty(KEY_DBURL) );
        result.setMaxActive( NumberUtils.toInt(prop.getProperty(KEY_MAX_ACTIVE), 20) );
        result.setMaxIdle( NumberUtils.toInt(prop.getProperty(KEY_MAX_IDLE), 30) );
        result.setMaxWait( NumberUtils.toInt(prop.getProperty(KEY_MAX_WAIT), 30) );
        result.setPassword( prop.getProperty(KEY_PASSWORD) );
        result.setUsername( prop.getProperty(KEY_USERNAME) );
        return result;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDbUrl() {
        return dbUrl;
    }

    public void setDbUrl(String dbUrl) {
        this.dbUrl = dbUrl;
    }

    public int getMaxActive() {
        return maxActive;
    }

    public void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMaxWait() {
        return maxWait;
    }

    public void setMaxWait(int maxWait) {
        this.maxWait = maxWait;
    }
}

星期二 五月 26, 2009

測試用的 Simple SQL in JSP

description

之前寫了介面給測試人員用, 但覺得還是不方便, 總不能每次都重新拉畫面給測試吧.
所以寫一個極簡易的 jsp, 直接下 SQL. 準備好 SQL 後請測試操作就可以了..
這還可以先選取要下的 SQL 再按送出查詢.
比方說你有兩行 SELECT, 可以選擇第一行 SELECT 命令後按送出, 就只會蒐尋第一個 SELECT.
如果都沒有選就會拿全部 textarea 裡面的東西去下 SQL.

codes


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="java.sql.*" %>
<%@page import="java.io.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">


<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        <script type="text/javascript">
            function takeTextAreaSelectionTextInto(textArea, target) {
                if ( !textArea || !target) { return; }
                var selectedText = (textArea.value).substring(textArea.selectionStart,textArea.selectionEnd);
                if ( selectedText == '' ) {
                    selectedText = textArea.value;
                }
                target.value = selectedText;
            }
            window.onload = function() {
                document.getElementById('sqlform').action = window.location;
            }
        </script>
        <style type="text/css">
            .body {
                font-size:small;
            }
        </style>
    </head>
    <body>
        <li> Firefox is preferred </li>
        <form method="POST" id="sqlform" name="sqlform"  action="">
            <table cellspacing="0" border="1">
                <tr>
                    <td style="background-color:silver;text-align:center;">
                        SQL
                        <input type="radio" name="type" value="query" ${param['type'] == 'query' ? 'checked' : ''} />Query
                        <input type="radio" name="type" value="update" ${param['type'] == 'update' ? 'checked' : ''}/>Update
                    </td>
                </tr>
                <tr>
                    <td>
                        <input type="hidden" name="sql" id="sql" value="${param['sql']}" />
                        <textarea style="font-size:smaller;" cols="80" rows="10" name="allsqls" id="allsqls">${param['allsqls']}</textarea><br />
                    </td>
                </tr>
                <tr>
                    <td style="background-color:silver;text-align:right;">
                        <input type="submit" onclick="takeTextAreaSelectionTextInto(document.getElementById('allsqls'), document.getElementById('sql'));" />
                    </td>
                </tr>
            </table><br />
            <%
        String driver = "org.apache.derby.jdbc.ClientDriver";
        String url = "jdbc:derby://localhost:1527/testPresure";
        String username = "testPresure";
        String password = "testPresure";
        String sql = request.getParameter("sql");
        String type = request.getParameter("type");
        System.out.println("[RemoteAddress]:" + request.getRemoteAddr());
        System.out.println("[SQL]:" + sql);
        if ( sql == null || "".equals(sql.trim()) ) {
            return;
        }
        Connection con = null;
        try {
            Class.forName(driver);
            con = DriverManager.getConnection(url, username, password);
            PreparedStatement pstmt = con.prepareStatement(sql);
            if ("query".equalsIgnoreCase(type)) {
                ResultSet rs = pstmt.executeQuery();
                ResultSetMetaData metaData = rs.getMetaData();
                out.println("<table border=1 cellspacing=0 style='font-size:small;text-align:center;'>");
                out.println("<tr>");
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    out.println("<td>" + metaData.getColumnName(i) + "</td>");
                }
                out.println("</tr>");
                while (rs.next()) {
                    out.println("<tr>");
                    for (int i = 1; i <= metaData.getColumnCount(); i++) {
                        out.println("<td>" + rs.getString(i) + "&nbsp;</td>");
                    }
                    out.println("</tr>");
                }
                out.println("</table>");
            } else if ("update".equalsIgnoreCase(type)) {
                int updateRow = pstmt.executeUpdate();
                pstmt.close();
                pstmt = null;
                System.out.println("Update " + updateRow + " rows");
                out.println("Update " + updateRow + " rows");
            }
        } catch (Exception ex) {
            out.println(ex.getMessage());
            ex.printStackTrace();
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (Exception conex) {
                    conex.printStackTrace();
                } finally {
                    con = null;
                }
            }
        }
            %>
        </form>
    </body>
</html>

星期日 五月 03, 2009

BeansBinding - BindingHelper

description

久沒寫 swing 程式了, 但偶爾需要拿來寫些給測試人員操作的小程式,
這時候 beansbinding 就可以幫上忙, 加速小程式的開發.
因此有這個簡單的 BingingHelper,
要注意想用 beansbinding 需要把 java bean 加上 eventListener.

codes

package test;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.Binding;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.beansbinding.Bindings;
import org.jdesktop.beansbinding.Converter;

public class BindingHelper {

    public static boolean sourceChanged(Object oldValue, Object newValue) {
        return !(new EqualsBuilder()).append(oldValue, newValue).isEquals();
    }

    public static void addBinding(Object src, String srcProp, Object dst, String dstProp, Converter converter, BindingGroup bindingGroup) {
        Binding binding = Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, src, BeanProperty.create(srcProp), dst, BeanProperty.create(dstProp));
        binding.setConverter(converter);
        bindingGroup.addBinding(binding);
    }

    public static void addReadOnceBinding(Object src, String srcProp, Object dst, String dstProp, Converter converter, BindingGroup bindingGroup) {
        Binding binding = Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_ONCE, src, BeanProperty.create(srcProp), dst, BeanProperty.create(dstProp));
        binding.setConverter(converter);
        bindingGroup.addBinding(binding);
    }

    public static void addReadOnlyBinding(Object src, String srcProp, Object dst, String dstProp, Converter converter, BindingGroup bindingGroup) {
        Binding binding = Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, src, BeanProperty.create(srcProp), dst, BeanProperty.create(dstProp));
        binding.setConverter(converter);
        bindingGroup.addBinding(binding);
    }

    public static void addReadOnceBinding(Object src, String srcProp, Object dst, String dstProp, BindingGroup bindingGroup) {
        Binding binding = Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_ONCE, src, BeanProperty.create(srcProp), dst, BeanProperty.create(dstProp));
        bindingGroup.addBinding(binding);
    }

    public static void addReadOnlyBinding(Object src, String srcProp, Object dst, String dstProp, BindingGroup bindingGroup) {
        Binding binding = Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, src, BeanProperty.create(srcProp), dst, BeanProperty.create(dstProp));
        bindingGroup.addBinding(binding);
    }
}

星期三 四月 29, 2009

HttpClient 登入後取得 struts TOKEN 再上傳檔案

description

面對一個 struts 做的 https 網站, 如果要自動 submit 檔案,
在之前還要先登入, 該怎麼做呢?
POC 一下, 感覺做出來真爽. 不過 HttpClient 的開發人員真是強啊..
網路上應該可以分別查到這些資料, 還是分享一下.

codes

public class TestUploadFile {

    public static void main(String[] args) {
        try {
            TestUploadFile test = new TestUploadFile();
            test.test();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void test() throws IOException {
        HttpClient client = new HttpClient();
        client.getHostConfiguration().setHost("www.xxx.com", 443, "https");
        login( client );
        uploadFile( client, token(client) );
    }

    private String token(HttpClient client) throws IOException {
        PostMethod filePost = new PostMethod("/xxx/xx.do?action=token");
        System.out.println("[token]" + client.executeMethod(filePost));
        String responseString = IOUtils.toString(filePost.getResponseBodyAsStream());
        filePost.releaseConnection();
        return trimToTokenVal(responseString);
    }

    private void uploadFile(HttpClient client, String token) throws FileNotFoundException, IOException {
        PostMethod filePost = new PostMethod("/xxx/xx.do?action=uploadFile");
        filePost.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE,true);
        Part[] parts = new Part[]{
            new StringPart("org.apache.struts.taglib.html.TOKEN", token),
            new FilePart("fileInputTagName", new File("filePath"))
        };
        filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
        System.out.println("[upload]" + client.executeMethod(filePost));
        filePost.releaseConnection();
    }

    private String trimToTokenVal(String responseString) {
        if ( StringUtils.isBlank(responseString) ) { return ""; }
        String tokenInputTag = responseString.substring(responseString.indexOf("<input type=\"hidden\" name=\"org.apache.struts.taglib.html.TOKEN\""), responseString.indexOf(">", responseString.indexOf("<input type=\"hidden\" name=\"org.apache.struts.taglib.html.TOKEN\"")+1));
        String tokenInutVal = tokenInputTag.substring(tokenInputTag.indexOf("value=\""), tokenInputTag.lastIndexOf("\""));
        tokenInutVal = tokenInutVal.substring(tokenInutVal.indexOf("\"")+1);
        return tokenInutVal;
    }

    private void login(HttpClient client) throws IOException {
        PostMethod post = new PostMethod("/xx/xx.do?action=login");
        NameValuePair[] data = {
            new NameValuePair("j_username","username"),
            new NameValuePair("j_password","password") };
        post.setRequestBody(data);
        System.out.println("[login]" + client.executeMethod(post));
        post.releaseConnection();
    }

}

星期六 四月 04, 2009

excel reader/writer adapter with javabean

description

分享一個自己寫的簡單處理 java bean 字串型態欄位與 excel 讀寫的程式.
使用這個可以省掉很多 getter/setter 的呼叫, 也不用準備很多 poi 的基礎程式. 不過一行excel 一個 java bean, 要更豐富的話可能就直接操作 poi 吧. 下載 source 與 test

reference

用到的 library 有 commons-io-1.4, commons-lang-2.4, poi-3.2

codes

user code 可看 unit test. 如下所示
public class ExcelWriterTest extends TestCase {

    public void testWriteTemplate() throws FileNotFoundException, IOException {
        List<MyPerson> persons = new ArrayList<MyPerson>();
        persons.add( createMyPerson("age", "qq@com", 5, "Mike") );
        persons.add( createMyPerson("age2", "q2q@com", 9, "Cute") );
        InputStream templateInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("tw/sdt/excel/testTemplate.xls");
        SDTContext writerContext = ExcelContext.newWriterContext(templateInputStream, 1, ExcelContext.NO_LIMIT, 0, null,
                new String[]{
                    MyPerson.PROP_AGE,
                    MyPerson.PROP_MAIL,
                    MyPerson.PROP_MONEY_TEXT,
                    MyPerson.PROP_NAME,
                } );
        SDTWriter writer = new ExcelWriter();
        OutputStream out = new FileOutputStream(new File("build/testTemplate.xls"));
        writer.write(writerContext, persons, out);

        SDTReader reader = new ExcelReader();
        SDTContext readerContext = ExcelContext.newReaderContext(new FileInputStream(new File("build/testTemplate.xls")), 1, ExcelContext.NO_LIMIT, 0,
                new String[]{
                    MyPerson.PROP_AGE,
                    MyPerson.PROP_MAIL,
                    MyPerson.PROP_MONEY_TEXT,
                    MyPerson.PROP_NAME,
                });
        Collection<MyPerson> mypersons = reader.read(MyPerson.class, readerContext);
        MyPerson[] mypersonAry = mypersons.toArray(new MyPerson[2]);
        assertEquals( "age", mypersonAry[0].getMyAge() );
        assertEquals( "qq@com", mypersonAry[0].getMyMail() );
        assertEquals( 5, mypersonAry[0].getMyMoney() );
        assertEquals( "Mike", mypersonAry[0].getMyName() );
        assertEquals( "age2", mypersonAry[1].getMyAge() );
        assertEquals( "q2q@com", mypersonAry[1].getMyMail() );
        assertEquals( 9, mypersonAry[1].getMyMoney() );
        assertEquals( "Cute", mypersonAry[1].getMyName() );
    }

    public void testWriteMyPerson() throws FileNotFoundException, IOException {
        List<MyPerson> persons = new ArrayList<MyPerson>();
        persons.add( createMyPerson("age", "qq@com", 5, "Mike") );
        persons.add( createMyPerson("age2", "q2q@com", 9, "Cute") );

        SDTContext context = ExcelContext.newWriterContext(ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT,
                new String[]{
                    "年齡",
                    "信箱",
                    "金額",
                    "姓名",
                }, new String[]{
                    MyPerson.PROP_AGE,
                    MyPerson.PROP_MAIL,
                    MyPerson.PROP_MONEY_TEXT,
                    MyPerson.PROP_NAME,
                } );
        SDTWriter writer = new ExcelWriter();
        OutputStream out = new FileOutputStream(new File("build/test.xls"));
        writer.write(context, persons, out);

        context = ExcelContext.newReaderContext(new FileInputStream(new File("build/test.xls")),
                ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT,
                new String[]{
                    MyPerson.PROP_AGE,
                    MyPerson.PROP_MAIL,
                    MyPerson.PROP_MONEY_TEXT,
                    MyPerson.PROP_NAME,
                } );
        SDTReader reader = new ExcelReader();
        Collection<MyPerson> personCollection = reader.read(MyPerson.class, context);
        MyPerson[] personAry = personCollection.toArray(new MyPerson[0]);
        assertEquals( personAry[1].getMyAge(), "age" );
        assertEquals( personAry[1].getMyMail(), "qq@com" );
        assertEquals( personAry[1].getMyName(), "Mike" );
        assertEquals( personAry[1].getMyMoney(), 5 );
        assertEquals( personAry[2].getMyAge(), "age2" );
        assertEquals( personAry[2].getMyMail(), "q2q@com" );
        assertEquals( personAry[2].getMyName(), "Cute" );
        assertEquals( personAry[2].getMyMoney(), 9 );
    }

    private MyPerson createMyPerson(String myAge, String myMail, int myMoney, String myName) {
        MyPerson result = new MyPerson();
        result.setMyAge(myAge);
        result.setMyMail(myMail);
        result.setMyMoney(myMoney);
        result.setMyName(myName);
        return result;
    }

    public void testWrite() throws FileNotFoundException, IOException {
        List<Person> persons = new ArrayList<Person>();
        persons.add( createPerson("11", "173", "男", "qq@mm.com", "QQ人", "智謀型") );
        persons.add( createPerson("35", "220", "女", "bb@s.com", "啦拉人", "美豔型") );

        SDTContext context = ExcelContext.newWriterContext(ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT,
                new String[]{
                    "年齡",
                    "身高",
                    "信箱",
                    "性別",
                    "姓名",
                    "類型"
                }, new String[]{
                    Person.PROP_AGE,
                    Person.PROP_HEIGHT,
                    Person.PROP_MAIL,
                    Person.PROP_MALE,
                    Person.PROP_NAME,
                    Person.PROP_TYPE
                } );
        SDTWriter writer = new ExcelWriter();
        OutputStream out = new FileOutputStream(new File("build/test.xls"));
        writer.write(context, persons, out);

        context = ExcelContext.newReaderContext(new FileInputStream(new File("build/test.xls")),
                ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT, ExcelContext.NO_LIMIT,
                new String[]{
                    Person.PROP_AGE,
                    Person.PROP_HEIGHT,
                    Person.PROP_MAIL,
                    Person.PROP_MALE,
                    Person.PROP_NAME,
                    Person.PROP_TYPE
                } );
        SDTReader reader = new ExcelReader();
        Collection<Person> personCollection = reader.read(Person.class, context);
        Person[] personAry = personCollection.toArray(new Person[0]);
        assertEquals( personAry[0].getAge(), "年齡" );
        assertEquals( personAry[0].getHeight(), "身高" );
        assertEquals( personAry[0].getMail(), "信箱" );
        assertEquals( personAry[0].getIsMale(), "性別" );
        assertEquals( personAry[0].getName(), "姓名" );
        assertEquals( personAry[0].getType(), "類型" );
        assertEquals( personAry[1].getAge(), "11" );
        assertEquals( personAry[1].getHeight(), "173" );
        assertEquals( personAry[1].getMail(), "qq@mm.com" );
        assertEquals( personAry[1].getName(), "QQ人" );
        assertEquals( personAry[1].getType(), "智謀型" );
    }

    private Person createPerson(String age, String h, String male, String mail, String n, String t) {
        Person p = new Person();
        p.setAge( age );
        p.setHeight( h );
        p.setIsMale( male );
        p.setMail( mail );
        p.setName( n );
        p.setType( t );
        return p;
    }

}

星期二 二月 03, 2009

推薦 - PointLayout project

雖然 MigLayout 已經很好了, 可是看起來 PointLayout 在微調的部份也很不錯.
PointLayout project
Transaction strategies: Understanding transaction pitfalls

星期日 一月 11, 2009

struts1 - LazyValidatorForm 基礎

description

最近用 struts1, 用了 LazyValidatorForm. 原本以為我可以把自己的 java bean 放進 form 裡面. 比方說
form.set("company", new Company());
    
把值放到畫面上, 輸入之後再用
form.get("company");
    
帶回來, 結果發現不行, 會有
java.lang.IllegalArgumentException: No bean specified
        at org.apache.commons.beanutils.PropertyUtilsBean.getPropertyDescriptor(PropertyUtilsBean.java:751)
        at org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:937)
...
    
的錯誤. 也沒深究. 總之後來看到原來 LazyValidatorForm 裡面的都是 LazyDynaBean. 所以我想要放 LazyDynaBean 才可以.
可是我又想要用有意義的 java bean, 就像是 Customer. 不想一堆 DynaBean. 就發現我把自己的 javabean 放進 List 就是一總解法.
不過當然目前我的 java bean 都是基礎型態 String. 但若目的只是要抓畫面上的直應該夠了吧..如果有更好的方式請 struts 高手指點一下. 我就蠻想用到整個畫面一個 javabean 就好, 所以 Company 裡面可能需要一堆 Dep 不知道怎樣做才是好方式. 謝謝

codes

準備輸入值的 action method
public ActionForward keyin(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {
    return mapping.findForward("keyin");
}
    
跑到 keyin.jsp
<html:form action="/test.do?m=test">
    <html:text property="companies[0].name" />
    <html:text property="friends[0].friendName" /><br />
    <html:text property="friends[1].friendName" /><br />
    <html:text property="friends[2].friendName" /><br />
    <html:text property="friends[3].friendName" /><br />
    <html:text property="friends[4].friendName" /><br />
    <html:text property="friends[0].friendEmail" /><br />
    <html:text property="friends[1].friendEmail" /><br />
    <html:text property="friends[2].friendEmail" /><br />
    <html:text property="friends[3].friendEmail" /><br />
    <html:text property="friends[4].friendEmail" /><br />
    <html:submit />
</html:form>
    
submit 後呼叫的 action method
public ActionForward test(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {
    LazyValidatorForm lazyForm = (LazyValidatorForm) form;
    List<Friend> friends = (List<Friend>) lazyForm.get("friends");
    List<Company> companies = (List<Company>) lazyForm.get("companies");
    lazyForm.set("friends", friends);
    lazyForm.set("companies", companies);
    return mapping.findForward( "success" );
}
    
最後顯示在 success.jsp
<bean:write name="lazyForm" property="companies[0].name" /><br />
<logic:iterate id="friend" name="lazyForm" property="friends">
    <bean:write name="friend" property="friendName" /><br />
</logic:iterate>
    

星期日 十一月 16, 2008

筆記 - 換 TimeZone 就自動算當地時間

reference

如何正確取得Dallas時間?

description

剛剛在論壇上看到, 記錄一下.
因為之前也想過這個問題, 原來是這麼使用法. 感恩~

codes

public class TestTime {

    public static void main(String[] args) {
        TimeZone currentTZ = TimeZone.getDefault();
        TimeZone tz = TimeZone.getTimeZone("America/Chicago");
        TimeZone.setDefault(tz);
        System.out.println(Calendar.getInstance().getTime());
        
        TimeZone.setDefault( currentTZ );
        System.out.println(Calendar.getInstance().getTime());
    }
}

星期日 九月 07, 2008

使用 java.util.Timer 指定時間執行

description

如果可以不用工具就不想用, jdk 已經有 Timer 了沒必要就不想加 jar 檔.
如果用在 web server 等地方, 注意最後要把 timer cancel 與 purge,
不然 instance 會一直存在到 server 關閉.

reference

java.util.Timer

codes

public class TestTimer {
    
    public static void main(String[] args) {
        TestTimer test = new TestTimer();
        test.test();
    }
    
    private void test() {
        new Timer().schedule( new ShowTimeTask(), firstRunTime(  9, 0 ), oneDayAsPeriod() );
        new Timer().schedule( new ShowTimeTask(), firstRunTime( 12, 0 ), oneDayAsPeriod() );
        new Timer().schedule( new ShowTimeTask(), firstRunTime( 18, 0 ), oneDayAsPeriod() );
        new Timer().schedule( new ShowTimeTask(), firstRunTime( 23, 0 ), oneDayAsPeriod() );
    }
    
    private Date firstRunTime(int hourOfDay, int minute) {
        Calendar c = Calendar.getInstance();
        int thisYear = c.get(Calendar.YEAR);
        int monthOfYear = c.get(Calendar.MONTH);
        int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
        c.set(thisYear, monthOfYear, dayOfMonth, hourOfDay, minute, 0);
        System.out.println("specific first run time : " + c.getTime());
        return c.getTime();
    }
    
    private long oneDayAsPeriod() {
        long ms = 1;
        long second = 1000 * ms;
        long minute = 60 * second;
        long hour = 60 * minute;
        long day = 24 * hour;
        return day;
    }
    
}

class ShowTimeTask extends TimerTask {

    @Override
    public void run() {
        showTime();
    }

    private void showTime() {
        System.out.println("Run at " + Calendar.getInstance().getTime());
    }
}