low level programmer

Main | Next month (Jul 2009) »
星期一 六月 15, 2009

Tomcat 用 ImageIO 讀圖要有 temp 資料夾

今天遇到一個狀況就是無法在 Tomcat 上用 ImageIO 讀圖片, 出現

javax.imageio.IIOException: Can't create cache file!
	javax.imageio.ImageIO.createImageInputStream(ImageIO.java:333)
	javax.imageio.ImageIO.read(ImageIO.java:1321)
	org.apache.jsp.test_jsp._jspService(test_jsp.java:65)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
讓人大吃一驚, 因為原本程式都跑好好的.
試了半天去 google 總算找到原因.
原來是要確保 $CATALINA_BASE/temp 這個資料夾存在
(如果有另外設定不要放 temp 放其他地方, 就是該設定的資料夾要存在)
IIOException can’t create cache file


就像他說的: Who would guess that doing PNG conversion with JDK APIs requires you to have a temp folder off of $CATALINA_BASE?

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;
    }

}

星期二 六月 09, 2009

依不同環境包檔案的 build.xml

description

為了部署方便, 參考 maven 的資料夾結構.
src/main/java
src/main/resources
src/main/config-dev
src/main/config-uat
src/main/config-prod
src/main/webapp
src/test/java
src/test/resources
寫了這個 build.xml 來依照部署的環境包檔案.

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="fubon-sportslotto-activity-200907" default="default" basedir=".">
    <description>Builds the project myp.</description>
    <property name="project.name" value="myp" />
    <property name="dist" value="dist" />
    <property name="build" value="build" />
    <property name="lib" value="lib" />
    <property name="build.test" value="build/test" />
    <property name="build.web" value="build/web" />
    <property name="build.web.classes" value="${build.web}/WEB-INF/classes" />
    <property name="build.web.lib" value="${build.web}/WEB-INF/lib" />
    <property name="main.resources" value="src/main/resources" />
    <property name="src.java" value="src/main/java" />
    <property name="src.config.dev" value="src/main/config-dev" />
    <property name="src.config.uat" value="src/main/config-uat" />
    <property name="src.config.prod" value="src/main/config-prod" />
    <property name="src.webapp" value="src/main/webapp" />
    <path id="build.classpath">
        <fileset dir="${lib}" includes="*.jar" />
    </path>
    <target name="clean">
        <delete dir="${build}" />
        <delete dir="${dist}" />
    </target>
    <target depends="clean" name="clean-dist">
        <mkdir dir="${build.web.classes}" />
        <mkdir dir="${dist}" />
        <javac destdir="${build.web.classes}" 
                srcdir="${src.java}"
                classpathref="build.classpath"
                source="1.5"
                target="1.5"
                encoding="UTF-8">
        </javac>
        <copy todir="${build.web.classes}">
            <fileset dir="${src.java}">
                <include name="**/*.xml"/>
            </fileset>
        </copy>        
        <copy todir="${build.web.lib}">
            <fileset dir="${lib}" />
        </copy>
        <copy todir="${build.web}">
            <fileset dir="${src.webapp}" />
        </copy>
    </target>

    <target depends="clean-dist" name="clean-dist-uat">
        <copy todir="${build.web.classes}">
            <fileset dir="${src.config.uat}" />
        </copy>        
        <war destfile="${dist}/${project.name}.war">
            <fileset dir="${build.web}" />
        </war>
    </target>

    <target depends="clean-dist" name="clean-dist-dev">
        <copy todir="${build.web.classes}">
            <fileset dir="${src.config.dev}" />
        </copy>        
        <war destfile="${dist}/${project.name}.war">
            <fileset dir="${build.web}" />
        </war>
    </target>
    
    <target depends="clean-dist" name="clean-dist-prod">
        <copy todir="${build.web.classes}">
            <fileset dir="${src.config.prod}" />
        </copy>        
        <war destfile="${dist}/${project.name}.war">
            <fileset dir="${build.web}" />
        </war>
    </target>
    
</project>

星期一 六月 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;
    }
}

星期二 六月 02, 2009

幾個 td 一個 tr 的邏輯

description

常遇到這種幾個 td 要一個 tr, 排版要整齊的邏輯.
雖然蠻簡單的, 可是都要想一下.
乾脆整理記錄起來

codes


package test;

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


public class TestTrTdWrap {
    
    public static void main(String[] args) {
        TestTrTdWrap test = new TestTrTdWrap();
        test.test();
    }

    private void test() {
        System.out.println("test 1 items 2 td wrap");
        showTrTd( takeItems(1), 2 );
        System.out.println("test 7 items 3 td wrap");
        showTrTd( takeItems(7), 3 );
        System.out.println("test 7 items 2 td wrap");
        showTrTd( takeItems(7), 2 );
        System.out.println("test 17 items 9 td wrap");
        showTrTd( takeItems(17), 9 );
        System.out.println("test 17 items 2 td wrap");
        showTrTd( takeItems(17), 2 );
    }

    private List<Item> takeItems(int cnt) {
        List<Item> items = new ArrayList<Item>();
        for ( int i = 0; i < cnt; i++ ) {
            items.add( new Item() );
        }
        return items;
    }

    private void showTrTd(List<Item> items, int tdWrap) {
        int itemSize = items.size();
        int roundCnt = itemSize + ( tdWrap - (itemSize % tdWrap) );
        for ( int i = 0; i < roundCnt; i++ ) {
            if ( i % tdWrap == 0 ) {
                System.out.println("<tr>");
            }
            if ( itemSize > i ) {
                System.out.printf("    <td>%s</td>%n", items.get(i).getContent());
            } else {
                System.out.println("    <td> </td>");
            }
            if ( i % tdWrap == tdWrap - 1 ) {
                System.out.println("</tr>");
            }
        }
    }

}
class Item {
    private String content = "testContent";
    public String getContent() {
        return content;
    }
}