25 12月 2009

Callback just like?

這篇想寫有段時間了,因為前兩週有個工作多年的同行在問,callback是什麼....但一直沒寫的原因是不想畫圖,不想寫sample code...

Callback是什麼?看起來很容易啊,就"叫回去"咩...似乎"回去叫"比較符合文法,這是簡單基本的東西,連Design Pattern都不屑列進去,但是只寫Java的人可能比較不能想像,因為Java沒有function pointer,所以比較不容易舉例,反而是寫過C(++),JavaScript的人比較容易理解.

簡單說, Callback就是將function當做參數傳給被呼叫的程式, 只碰Java的應該就頭大了,將function(method)當參數?!

先談談程式運作的模式吧,用別人的Library寫系統有幾種方式,

一是事必躬親,站在旁邊看著別人做完一步,再決定下一步要做什麼

二是先告訴對方我是誰,能做什麼事,等他有空時要處理我的工作時候再叫我過去

三是留紙條給他,叫他照著辦,心情好再留個電話給他,叫他辦完時要回報一下

第一種情形像什麼,用過JDBC library的應該很清楚,

Connection conn = ds.getConnection(...);
PreparedStatement preStat = conn.prepareStatement(...);
preStat.setObject(....)
....
preStat.execute();
conn.close();
很熟悉吧?

第二種情形呢,比較像是用Observer Pattern來做事

interface Observable {
 public void notifyObservers();
 public void register(Observer obs);
 public void unRegister(Observer obs);
}
interface Observer {
 public void available(Observable ob);
}

Observable利用Observer.available()來告訴Observer說我現在有空了,一起來玩吧...當然也可以讓Observable呼叫Observer的其他method來做事,只是這代表這兩個人要夠熟,不過由於是別人寫的API,所以Observable要完全認識你所寫Observer的機會不太高,只好將這定成Interface,能做的事情都定在Interface上囉

第三種就直接明瞭

class ThatCallsBack:public class Caller{
public:
 ThatCalls(T *who,void (T::*func)(void)):
  callee(who),callback(func){}
 void click()
  {(callee->*callback)();}
private:
 T *callee;
        void (T::*callback)(void);
};
我就給你一個Function跟我的大名,自己看著辦!酷!

二三這兩種模式在Multithread的系統經常被使用,但Java缺少了關鍵性的function pointer,所以怎麼看都少了點fu.雖然Java沒有function pointer,但利用第二種做法還是可以寫出很有callback fu的API,第一種模式寫的JDBC程式可以改成下面這樣

Interface CallbackStatement {
 String hereIsMyStatement();
 Object[] hereAreMyParameters();
 void letMeKnowIfThereIsAnyProblem(String msg);
}

Interface SQLExecutor() {
 void execute(CallbackStatement cs);
}
這樣勉強算是callback吧,其實Spring的JDBCTemplate就是大量用這種方式來工作的喲

04 12月 2009

病貓

有人跟我抱怨為什麼用Eclipse + m2eclipse deploy web project到tomcat時,老是㑹將servlet-api-XXX.jar跟jsp-api-XXX.jar丢到WEB-INF/lib下,結果tomcat就變成起不來的病貓,可是經我個人反覆測試,pom.xml中的dependency只要有加<scope>provided</scope>,一定不㑹被丟到WEB-INF/lib。

遇到這種見鬼的事情,第一件要做的事當然是...拿乖乖去拜你的電腦(誤

有幾個選擇可以解決

(1)自己砍掉WEB-INF/lib中的servlet-api.jar jsp-api.jar,缺點是每次你有改變dependency時就要再做一次。

(2)將serlvet-api跟jsp-api的dependency的設定移到profile中,然後在project->Java build path->Libraries->Add Library
選server runtime,再選tomcat,將tomcat runtime libraries加入你的project libraries,這樣的缺點是每次用Maven都要記得加 -P。

BTW,乖乖團購有比較便宜嗎?

20 11月 2009

Apache2 mod_ssl : SSLPassPhraseDialog

最近都在處理platform的事,好像很久沒coding...

SSL的private key可以用來保護,但在一般server上為了方便,常㑹使用去除Pass Phrase的key,否則每次啟動都要輸入Pass Phrase,對我這種不太重視資安的人是比較麻煩些。

這次遇到的問題是Apache2 SSL module用的private key一定要用Pass Phrase,平時沒在用的功能,只好推說要回去確認,再回家拜請Google大神,不過答案在Apache2的mod_ssl文件中就很淸楚了


改一下mod_ssl.conf,只要把原來

SSLPassPhraseDialog builtin
改成
SSLPassPhraseDialog exec:/ect/apache2/key.sh #位置,檔名隨你高興

key.sh只要這様寫
#!/bin/bash
echo 'your pass phrase'
這様就解決囉

key.sh也不一定要是shell script,也可以用其他languae implement,重點是要把pass phrase寫入stdout。

11 11月 2009

How many open files on unix like server?

有人遇到開啟檔案超過上限的問題,就隨手列了下來,這應該只是一篇噗文就能解決的。。。

1.簡易計算法

unixlike$ lsof | wc -l
5124

2.正式確認法

unixlike$ cat /proc/sys/fs/file-nr
6144 0 125039
-------------
(1) (2) (3)
(1)The number of allocated file handles
(2)The number of allocated but unused file handles
(3)The maximum number of file handles

要修改可開啟的檔案數量上限,請修改/proc/sys/fs/file-max,這動作做完要重開就是了。開啟檔案超過上限這個問題通常只在server上會遇到,大部份處理platform的人應該都知道,這篇只能算是不專業筆記了。


補註:

果然是不專業筆記,馬上被糾正,開啟檔案上限除了系統預定的總量外,還有單一process的限制。

unixlike$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
open files就是單一process可以開啟的檔案上線,可以用
unixlike$ ulimit -n 10240 #將上限改為10240
unixlike$ ulimit -n unlimited #不限

27 10月 2009

emma-maven-plugin always executes test cases twice

這是碎碎唸
如果同時要出Emma Code Coverage跟Surefire Test report的話,一定要跑2次 Unit Test,聽起來很合理,但其實根本就不用。
只要在Surefire執行前先將test classes做instrument,這様測出來的就是具有coverage的unit test.
<plugin>
 <groupId>org.sonatype.maven.plugin</groupId>
 <artifactId>emma-maven-plugin</artifactId>
 <version>1.1</version>
 <inherited>true</inherited>
 <executions>
  <execution>
   <id>instrument</id>
   <phase>process-classes</phase>
   <goals>
    <goal>instrument</goal>
   </goals>
  </execution>
 </executions>
</plugin>
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-surefire-plugin</artifactId>
 <version>2.4.3</version>
 <inherited>true</inherited>
 <configuration>
  <forkMode>once</forkMode>
        <reportFormat>xml</reportFormat>
  <classesDirectory>${project.build.directory}/generated-classes/emma/classes</classesDirectory>
 </configuration>
</plugin>
這様跑完就㑹產生coverage.em, coverage.ec等產生Code Coverage Report所需要的東西。


而jira上也提出這個問題很久了…就是他X的沒人解決,
Allow generating reports outside the emma:emma goal


現在只好偷偷用emma4it-maven-plugin,單獨來跑report,只是不能出現在project reports裡
<plugin>
 <groupId>org.sonatype.maven.plugin</groupId>
 <artifactId>emma4it-maven-plugin</artifactId>
 <version>1.3</version>
 <executions>
  <execution>
   <id>report</id>
   <phase>post-integration-test</phase>
   <goals>
    <goal>report</goal>
   </goals>
   <configuration>
    <sourceSets>
     <sourceSet>
      <directory>${project.build.sourceDirectory}</directory>
     </sourceSet>
    </sourceSets>
   </configuration>
  </execution>
 </executions>
</plugin>

20 10月 2009

hibernate3-maven-plugin直接使用Spring AnnotationSessionFactoryBean

新公司有自己的一套Framework,並自行開發一套code gen的工具,稍為喚起了我曽經用過Hibernate Tools的記憶,一方面是因為用了JDK5的Generic後,要寫的Code變少,另一方面也是因為如果有修改,code gen出來的東西比較不易配合更動,所以也沒有納入我常用的工具之一。不過既然想起了Hibernate tools,那就再用用看有沒有什麼改變,或許會有驚喜吧。

不過似乎沒有…特別是不能直接用Spring Configuration Xml中已經訂好的設定,一定要另訂hibernate.cfg.xml,這就又讓我難過了一下,再發現居然連hibernate3-maven-plugin也無法直接使用Spring 裡訂好的AnnotationSessionFactoryBean或LocalSessionFactoryBean,只好試著改看看有沒有辦法可以讓我懶一點不要再去重訂hibernate.cfg.xml。


發現hibernate3-maven-plugin中有一個AnnotationComponentConfiguration,看來似是一個不錯的切入點,稍為改了一下還發現真能work!下面列的就是實做出來的東西。


1.pom.xml

改maven的plugin不用maven也太說不過去了吧,所以pom.xml是一定要的。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

 <modelVersion>4.0.0</modelVersion>

 <groupId>org.elliot.hibernate</groupId>
 <artifactId>maven-hibernate3-jdk15</artifactId>
 <version>1.0-SNAPSHOT</version>
 <name>Maven Hibernate3 Implementation - JDK15</name>
 <packaging>jar</packaging>
 <dependencies>
  <dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-model</artifactId>
   <version>2.0.6</version>
  </dependency>
  <dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-plugin-api</artifactId>
   <version>2.0.6</version>
  </dependency>
  <dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-artifact</artifactId>
   <version>2.0.6</version>
  </dependency>
  <dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-project</artifactId>
   <version>2.0.6</version>
  </dependency>
  <dependency>
   <groupId>org.codehaus.mojo.hibernate3</groupId>
   <artifactId>maven-hibernate3-jdk15</artifactId>
   <version>2.2</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>3.3.2.GA</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>3.4.0.GA</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>ejb3-persistence</artifactId>
   <version>1.0.2.GA</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-annotations</artifactId>
   <version>3.4.0.GA</version>
  </dependency>
  <dependency>
   <groupId>jboss</groupId>
   <artifactId>jboss-common</artifactId>
   <version>4.0.2</version>
  </dependency>
  <dependency>
   <groupId>javassist</groupId>
   <artifactId>javassist</artifactId>
   <version>3.4.GA</version>
  </dependency>
  <!--可視情形改用其他版本的Spring-->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.orm</artifactId>
   <version>3.0.0.RC1</version>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>
2. SpringComponentConfiguration.java

我暫用org.codehaus.mojo.hibernate3.configuration這package,怕AnnotationComponentConfiguration會不會有什麼method不能用,後來看code發現沒問題,也可以改成你喜歡的名稱

package org.codehaus.mojo.hibernate3.configuration;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.mojo.hibernate3.ExporterMojo;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.util.StringUtils;

public class SpringComponentConfiguration extends
  AnnotationComponentConfiguration {
 private static final Log logger = LogFactory
   .getLog(SpringComponentConfiguration.class);

 private ExporterMojo exporterMojo;
 private ApplicationContext applicationContext;

 public String getName() {
  return "springconfiguration";
 }

 public ExporterMojo getExporterMojo() {
  return exporterMojo;
 }

 public void setExporterMojo(ExporterMojo exporterMojo) {
  this.exporterMojo = exporterMojo;
 }

 @Override
 protected Configuration createConfiguration() {
  String sessionFactoryBean = getExporterMojo().getComponentProperty(
    "sessionFactoryBean", "sessionFactory");
  String appContextLocations = getExporterMojo().getComponentProperty(
    "appContextLocations", "classpath*:spring*.xml");
  logger.info("Initial info: [sessionFactoryBean]=" + sessionFactoryBean
    + ", [appContextLocations]=" + appContextLocations);

  String[] locations = StringUtils.delimitedListToStringArray(
    appContextLocations, ",");
  // Initial ApplicationContext from spring configuration xml files.
  this.applicationContext = new FileSystemXmlApplicationContext(locations);

  // Get AnnotationSessionFactoryBean from spring
  AnnotationSessionFactoryBean asfb = (AnnotationSessionFactoryBean) applicationContext
    .getBean("&" + sessionFactoryBean);

  DataSource dataSource = asfb.getDataSource();
  ThreadLocalHolder.setDataSource(dataSource);

  Configuration configuration = asfb.getConfiguration();
  configuration.setProperty(Environment.CONNECTION_PROVIDER,
    ThreadLocalConnectionProvider.class.getName());

  return configuration;
 }

 @Override
 protected void validateParameters() throws MojoExecutionException {
  // don't validate
 }

}
3.ThreadLocalConnectionProvider.java

因為Configuration不能直接設DataSource,所以只好放到ThreadLocal

package org.codehaus.mojo.hibernate3.configuration;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;

public class ThreadLocalConnectionProvider implements ConnectionProvider {
 private static final Log logger = LogFactory.getLog(ThreadLocalConnectionProvider.class);
 public ThreadLocalConnectionProvider() {
 }
 public void close() throws HibernateException {

 }

 public void closeConnection(Connection conn) throws SQLException {
  conn.close();
 }

 public void configure(Properties props) throws HibernateException {
  //Do nothing

 }

 public Connection getConnection() throws SQLException {
  DataSource dataSource = ThreadLocalHolder.getDataSource();
  if (null == dataSource) {
   logger.error("Please check ThreadLocalHolder.setDataSource has been invocked.");
   throw new SQLException("No usable DataSource.");
  }
  return dataSource.getConnection();
 }

 public boolean supportsAggressiveRelease() {
  // TODO Auto-generated method stub
  return true;
 }

}
4.ThreadLocalHolder.java

package org.codehaus.mojo.hibernate3.configuration;

import javax.sql.DataSource;

public abstract class ThreadLocalHolder {
 private static ThreadLocal<DataSource> dataSourceHolder = new ThreadLocal<DataSource>();

 public static DataSource getDataSource() {
  return dataSourceHolder.get();
 }

 public static void setDataSource(DataSource dataSource) {
  dataSourceHolder.set(dataSource);
 }
 
}
5.components.xml

這檔案放在src/main/resources/META-INF/plexus下,是maven plugin的設定檔

<component-set>
  <components>
 <component>
      <role>org.codehaus.mojo.hibernate3.configuration.ComponentConfiguration</role>
      <role-hint>springconfiguration</role-hint>
      <implementation>org.codehaus.mojo.hibernate3.configuration.SpringComponentConfiguration</implementation>
    </component>
  </components>
</component-set>
完成之後就用mvn install裝到repository裡以供使用,使用方式就只是改變hibernate3-maven-plugin中的dependency。

<build>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>hibernate3-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
     <componentProperties>
      <jdk5>true</jdk5>
      <implementation>springconfiguration</implementation>
      <appContextLocations>classpath*:applicationContext.xml</appContextLocations>
      <sessionFactoryBean>sessionFactory</sessionFactoryBean>
     </componentProperties>
    </configuration>
    <dependencies>
     <dependency>
      <groupId>org.elliot.hibernate</groupId>
      <artifactId>maven-hibernate3-jdk15</artifactId>
      <version>1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-ehcache</artifactId>
      <version>3.3.2.GA</version>
     </dependency>
     <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotations</artifactId>
      <version>3.4.0.GA</version>
     </dependency>
     <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.2.121</version>
     </dependency>
    </dependencies>
   </plugin>
  </plugins>
 </build>
加入configuration中列出的設定,appContextLocations是專案中spring設定檔的檔案位置,sessionFactoryBean則是spring中你定義的AnnotationSessionFactoryBean名稱。

再來就可以用mvn hibernate3:hbm2ddl 之類的goals來測試囉。

14 10月 2009

載入特定目錄下的jar做為CLASSPATH

一種是用FIND
#!/bin/sh

CLASSPATH=`find lib -name *.jar|xargs|sed "s/ /:/g"`
CLASSPATH=".:$CLASSPATH"
echo $CLASSPATH

另一種就是自己組囉…
#!/bin/sh

CLASSPATH=.
for file in lib/*;
do CLASSPATH=${CLASSPATH}:$file;
done
echo $CLASSPATH

18 9月 2009

碎碎唸(8)

一直來就想做件事,租個虛擬主機,掛個Apache + Subversion,這樣我在外頭也可以改改自High的demo,回家後也不用開MBP來sync程式到我的Desktop,但一方面是不確定是否能正常運作,一方面也不想多這筆開銷(在家用ADSL自己架?我可不想天天擔心家裡電器走火…),所以一直沒有付諸實行,但最近因為玩Ruby的關係,接觸到了GIT,發現有免錢的github,真是一整個高興!Eclipse上的pluging “egit”雖然有點不成材,但用git protocol來接github倒沒出什麼事,只可惜了我的iPhone 3GS,JB後裝的git 跟subversion 就沒什麼用了…

16 9月 2009

Nexus : Maven Repository Server

Nexus,一個Maven Repository Server,在區網內如果架設一個Nexus來提供開發人員使用,可以有效減少對外網路頻寬的浪費,也提供一個可以管理團隊自行開發library的機制,之前較多使用的是Apache Archiva,但是Archiva較為複雜,相較之下Nexus則無論在安裝上跟管理上都較為容易。 以下是我在Ubuntu 8.10 與 Tomcat 6.0.18下安裝的方式
  1. Download nexus-webapp-XXX.war
    • Nexus的下載頁面在 http://nexus.sonatype.org/downloads/ ,雖然Nexus也有自帶jetty的版本,但我還是打算使用webapp來安裝,所以下載的是nexus-webapp-XXX.war。
  2. Deploy nexus-webapp-XXX.war
    • 將war改名為nexus.war後直接丟到${tomcat}/webapp下就好。
  3. 設定sonatype-work權限 (各OS與distribution㑹有所不同)
    • 由於nexus需要實體目錄存放下載的檔案,所以㑹在/usr/share/tomcat6下建一個sonatype-work的目錄,但由於/usr/share/tomcat6的權限原屬於root,所以執行
      $> sudo mkdir /usr/share/tomcat6/sonatype-work
      $> sudo chown tomcat6:tomcat6 /usr/share/tomcat6/sonatype-work
      
      後再重起tomcat即可
  4. 再來是設定client端maven2用的setting.xml
    • 加入下面的xml到setting.xml,將其中tomcat_ip與tomcat_port改成你實際使用的
<mirrors>
    <mirror>
        <id>nexus</id>
        <mirrorOf>*</mirrorOf>
        <url>http://${tomcat_ip}:${tomcat_port}/nexus/content/groups/public</url>
    </mirror>
  </mirrors>
  <profiles>
    <profile>
    <id>nexus</id>
    <repositories>
        <repository>
            <id>central</id>
            <url>http://central</url>
            <releases><enabled>true</enabled></releases>
            <snapshots><enabled>true</enabled></snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>central</id>
            <url>http://central</url>
            <releases><enabled>true</enabled></releases>
            <snapshots><enabled>true</enabled></snapshots>
        </pluginRepository>
    </pluginRepositories>
    </profile>
  </profiles>
  <activeProfiles>
    <activeProfile>nexus</activeProfile>
  </activeProfiles>
這樣就有一個Maven Repository Server 可用了!
PS:Mac上的maven在mirror中如果用hostname對應ip似乎不正常,在/etc/hosts已經設好了,但是就是連不到,用curl與wget都沒問題…

04 9月 2009

Ubuntu & git-daemon

既然git是distributed revision control system, 所以除了server外,每個開發人員也應該要有完整的git操作環境,但不是每個開發人員都需要有apache這種httpd server,還好git本身有提供git-daemon來讓開發人員交流手上的source clone,git-daemon很容易,指定base-path就好,但是如果希望開機時自動載入的話可以試試安裝下這個package:
sudo apt-get insall git-daemon-run
安裝好了之後改一下 /etc/sv/git-daemon/run, 將"--base-path=xxxx"指到你git repositories 的root path, 然後在每一個你要share出來的git repository中下一個指令建立magic file
touch git-daemon-export-ok
沒有git-daemon-export-ok這檔案的repository是不會被別人看到的.
再重起git-daemon即可囉
sudo /etc/init.d/git-daemon restart

02 9月 2009

Maven2: Profile

通常在一個專案中,執行的環境通常不㑹只有一個,大多數的情形是3個,真正上線的Production環境,上線前的測試Staging環境,還有就是開發人員自己開發時用的Personal環境,所以在Package時自然應該要有不同的Script來處理不同環境下的設定檔,不然用人工的話很容易發生開發人員將Personal的設定檔包入Production要用的deployment file。Server起不來就算了,就怕滙入了什麼不該滙的,或是砍了什麼不能砍的…

早期使用Ant時,properties跟xml不是用merge就是用replace的,Maven的做法也不例外,只是Ant要寫不少個ant task,但Maven不用,當然,過於思念或割捨不下Ant時,仍然可以透過Ant run在Maven中讓你與Ant相逢。

下面舉個小小的例子,使用profile來區分不同的環境下使用的同名設定檔。 Project的Resources Structure如圖
profile_structure.tu4fAfcdsJOA.jpg
src/main/resources為production環境使用的設定檔,這個目錄也是Maven2預設的resources目錄
src/main/staging為上線前的staging璄環使用,
src/main/personal為開發人員本身所用的設定檔。
3個目錄中皆有一個同名的properties檔案:system.properties,其中內容有所不同
resources/system.properties

profile=production
staging/system.properties
profile=staging
personal/system.properties
profile=personal
而resources再多一個共用的設定檔exist.properties,用以確認在production之外的環境下除同名檔案被覆蓋外,其餘檔案仍正常存在,內容如下
exist=true

再寫一個簡易的JUnit Test Case
@RunWith(BlockJUnit4ClassRunner.class)
public class SampleTest {
   private ResourceBundle systemRb = null;
   private ResourceBundle existRb = null;
   @Before
   public void befor() {
       systemRb = ResourceBundle.getBundle("system");
       existRb = ResourceBundle.getBundle("exist");
   }
  
   @Test
   public void testResources() {
       System.out.println("profile for : "+this.systemRb.getString("profile"));
       System.out.println("check exist : " +this.existRb.getString("exist"));
   }
}
簡單地讀取system.properties及exist.properties,然後將profile及exist的值列出來而已。
再來看pom.xml

   
       
       
           
               src/main/resources
           
       
   

   
       
       
           staging
           
               
                   
                       src/main/staging
                       true
                   
               
           
       
       
       
           personal
           
               
                   
                       src/main/personal
                       true
                   
               
           
       
   

在profiles下定了staging及personal兩個profile,其中要注意的是<filtering>這個tag,雖說Maven是用這個值做為判斷是否要使用merge的依據,但設為true後㑹強制覆蓋同名檔案,這才是我希望的功能。
接下來只要在maven執行時加入-P<profile_id_1>即可,所以試著執行下列command看看結果

$> mvn clean test
-------------------------------------------------------
profile for : production
check exist : true
$> mvn -Pstaging clean test
-------------------------------------------------------
profile for : staging
check exist : true
$> mvn -Ppersonal clean test
-------------------------------------------------------
profile for : personal
check exist : true
三個結果很明顯地因為-P所帶的參數而有不同的結果

其他必需注意的,-P後面可以帶多個profile id,只要用逗號分隔即可,而profile除了區分resource外,還可以指定JDK版本,或是設定properties等作用,例如可以加上<maven.test.skip>true</maven.test.skip>來免除執行test。

MacJournal Test

Test for new tool - MacJournal....

    junit
    junit
    4.6
    jar
    compile

12 8月 2009

Spring3 Maven Repository

Spring repositories
由於Spring3還是在測試階段,所以並沒有把library放到多數公開的repository上,所以要取用的話必需加些repository到maven裡

<repositories>
    <repository>
        <id>SpringSource Enterprise Bundle Repository - External Bundle Milestones</id>
        <url>http://repository.springsource.com/maven/bundles/milestone</url>
    </repository>
    <repository>
        <id>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</id>
        <url>http://repository.springsource.com/maven/bundles/release</url>
    </repository>
    <repository>
        <id>SpringSource Enterprise Bundle Repository - External Bundle Releases</id>
        <url>http://repository.springsource.com/maven/bundles/external</url>
    </repository>
</repositories>

如果不知道有哪些library可以用,那可以透過下面這url確認一下

http://s3browse.com/explore/repository.springsource.com/maven/bundles/milestone/org/springframework/

06 8月 2009

為什麼VCS要能透過HTTP存取對我很重要

有朋友問著,Subversion用svn protocol,Git就用git protocol,設定起來不是比較容易嗎?

當然,在Intranet裡,通常你要怎麼用都沒問題,問題是當你離開辦公室後,或是特別的因素開發人員必需分隔兩地時,能不能透過HTTP來存取VCS就很重要了。

從公司內部來看,很少MIS會願意特別幫我在防火牆上去開svn, git要用的port,要不然也要經過相當麻煩的申請手續,除非我就是那個網路管理者。

從身在他地的人來看,如果是在自己家中還好,不會特別去關svn, git用到的port,但是如果是身在其他公司內會有網路使用限制的人,恐怕連pop3/smtp, ftp都不能連了,更不用提這些svn, git所用的port。

所以能透過最不容易被擋的HTTP存取VCS的重要性就在這囉。

Apache2 + SSL on Ubuntu 8.10

主要是參照SSL on Ubuntu 8.10 Apache2

(1)Open Apache SSL Module
sudo a2enmod ssl
(2)Create server's private key and certificate
cd /etc/apache2
sudo openssl genrsa -des3 -out server.key 1024
sudo openssl req -new -key server.key -out server.csr
sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
這時會問些國家、公司之類的問題,照著回答就OK了,回答的資料會顥示在Browser的憑證清單裡
(3)Install the key and certificate:
sudo cp server.crt /etc/ssl/certs/
sudo cp server.key /etc/ssl/private/
(4)Edit default-ssl configuration
sudo vim /etc/apache2/sites-available/default-ssl
add
SSLEngine on
SSLCertificateFile /etc/ssl/certs/server.crt
SSLCertificateKeyFile /etc/ssl/private/server.key
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
(5)Enable default-ssl and restart apache2
sudo a2ensite default-ssl
sudo /etc/init.d/apache2 restart

05 8月 2009

GIT + Apache2 on Ubuntu 8.10 (1)

前言
很早前就聽過GIT這個分散式的VCS,但是因為Subversion對我而言實在相當夠用,一直沒有想要更換的念頭,直到最近開始用了JRuby 才有了用用看的念頭,花了點時間確認GIT可以透過Apache走HTTP/HTTPS來checkin/checkout,而且Maven的SCM也支援GIT, 就開始了跟GIT奮戰的過程,我想至少花了4小時才確認這個GIT的Service是可用的。主要是因為不熟GIT的command,無法確認是否正 常。

安裝
(0)由於我已經有安裝了Apache2與Subversion,所以略過Apache2及DAV module的安裝,並且採用Subversion的帳號密碼檔

(1)安裝git-core curl

$>sudo apt-get install git-core curl

這時執行

$>git --version

應該會出現下到訊息,代表git應該可以用了
git version 1.5.6.3

再來是建立curl會用到帳密

$>touch ~/.netrc
然後在.netrc中加入下列資料

machine localhost
login youraccount #same with subversion
password yourpassword #same with subversion

(2)建立GIT repository

$>sudo mkdir /var/lib/git #先建一個git root,再將其他repository放在其下
$>sudo mkdir /var/lib/git/repo1
$>cd /var/lib/git/repo1
$>sudo git --bare init
$>sudo git-update-server-info
$>sudo chmod +x hooks/post-update #在透過http commit後會自動執行git-update-server-info
你會看到下列這樣的訊息,代表init成功
Initialized empty Git repository in /var/lib/git/repo1/
再設定權限,讓Apache2可以存取
$>sudo chown www-data:www-data -R /var/lib/git

(3)enable apache2 dav_fs, dav module
$>sudo a2enmod dav_fs
$>sudo a2enmod dav
因為我已經有裝Subversion,想說應該不用設定才是,後來發現只有起用dav這個module,而dav_fs沒起用,就是不行
所以還是記得要確認一下

(4)config git dav
建立Apache2用的GIT DAV設定
$>sudo touch /etc/apache2/mods-available/dav_git.conf
$>sudo ln -s /etc/apache2/mods-available/dav_git.conf /etc/apache2/mods-enabled/dav_git.conf
然後修改/etc/apache2/mods-available/dav_git.conf,將在第2個Step中加入的GIT Repository設為DAV,並指定
HTTP連結路徑為/git/repo1

Alias /git "/var/lib/git"
<Location /git/repo1>
	DAV on
	AuthType Basic
	AuthName "Git Repository"
	AuthUserFile "/etc/apache2/dav_svn.passwd"
	Require valid-user
</Location>

(5)restart apache2

$>sudo /etc/init.d/apache2 restart
這時再用Browser連結http://localhost:8080/git/repo1/HEAD,輸入帳密後應該可以看見下列訊息
ref: refs/heads/master

(6)clone repo1
在任一空目錄下執行git clone

$>git clone http://localhost/git/repo1
應該可以看到
Initialized empty Git repository in /yourpath/repo1/.git/
warning: You appear to have cloned an empty repository.

(7)test commit

$>touch readme
$>git add readme
$>git commit -m "first"
[master (root-commit) 29db40b] first
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 readme
$>git push origin master
Fetching remote heads...
refs/
refs/heads/
refs/tags/
updating 'refs/heads/master'
from 0000000000000000000000000000000000000000
to 29db40b949a69400ea4377c28703b6073c91d785
sending 3 objects
done
Updating remote server info

29 7月 2009

其實,我想知道你聽到的是什麼

以下這對話經常出現在我高中下課後

我:香草霜淇淋一個

店員:先生,請問你要什麼口味

我:…

我真的很想知道,你們聽到的是什麼

24 7月 2009

APR for Tomcat6 on Ubuntu 8.10

常用Tomcat的朋友對下面的WARN Message應該不陌生
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production
environments was not found on the java.library.path:
/usr/java/packages/lib/i386:/lib:/usr/lib:/usr/lib/jni
如果不理他其實也沒什麼影響,只是看久了也會難過,依以往用tomcat的經驗,就是download apr的source,再make install就好了,不過還是Google了一下,果然發現Ubuntu有自帶的package,還好沒做白工自己compile,然後就很開心的執行了下面的cmd
sudo apt-get install libtcnative-1
再來就是重起tomcat6了。 暗,居然開不起來
Jul 24, 2009 3:22:12 PM org.apache.coyote.http11.Http11AprProtocol start
SEVERE: Error starting endpoint
java.lang.Exception: Socket bind failed: [22] Invalid argument
 at org.apache.tomcat.util.net.AprEndpoint.init(AprEndpoint.java:612)
.....
 at org.apache.commons.daemon.support.DaemonLoader.start(DaemonLoader.java:177)
心理想,這是什麼東西....只好再拜請Google大神了。 修改 /etc/modprobe.d/aliases,找出
alias net-pf-10 ipv6
改成
alias net-pf-10 off
再重起電腦就OK。

21 7月 2009

介於陰影與靈魂之間

------------------------------------------------------------------------------

【聶魯達一百首情詩-17】 聶魯達著/陳黎‧張芬齡譯

我愛你,但不把你當成玫瑰,或黃寶石,
或大火射出的康乃馨之箭。
我愛你,像愛戀某些陰暗的事物,
秘密地,介於陰影與靈魂之間。

我愛你,把你當成永不開花
但自身隱含花的光芒的植物;
因為你的愛,某種具體的香味
自大地升起,暗自生活於我的體內。

我愛你,不知該如何愛,何時愛,打哪兒愛起。
我對你的愛直截了當,不複雜也不傲慢;
我如是愛你,因為除此之外我不知道

還有什麼方式:我不存在之處,你也不存在,
如此親密,你擱在我胸前的手便是我的手,
如此親密,我入睡時你也闔上雙眼。

------------------------------------------------------------------------------

我想你明白,我會一直,往有你的地方走去。

logback: 將各個log file依日期存放在同一目錄

偶爾會有這樣的需求,希望同一天的Log都在同一個目錄下,這時只要將TimeBasedRollingPolicy的FileNamePattern用
%d{yyyy/MM/dd/}/這類的Pattern就可以達成囉。

請見以下例子
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
	<appender name="SYSTEM" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<Prudent>true</Prudent>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<FileNamePattern>%d{yyyy/MM/dd/}/System.log</FileNamePattern>
		</rollingPolicy>
		<layout class="ch.qos.logback.classic.PatternLayout">
			<Pattern>%d [%thread] %-5level %logger{35} - %msg%n
			</Pattern>
		</layout>
	</appender>
	<appender name="MAIL" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<Prudent>true</Prudent>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<FileNamePattern>%d{yyyy/MM/dd/}/Mail.log</FileNamePattern>
		</rollingPolicy>
		<layout class="ch.qos.logback.classic.PatternLayout">
			<Pattern>%d [%thread] %-5level %logger{35} - %msg%n
			</Pattern>
		</layout>
	</appender>
	<root level="INFO">
		<appender-ref ref="SYSTEM" />
		<appender-ref ref="MAIL" />
	</root>
</configuration>

20 7月 2009

logback 二、三事

(1)要用Logback當然就一併用slf4j,Maven2的dependencies就加入:

<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>0.9.16</version>
	<type>jar</type>
</dependency>
<!-- 用以取代commons-logging -->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jcl-over-slf4j</artifactId>
	<version>1.5.8</version>
	<type>jar</type>
</dependency>
<!-- 用以取代Log4j,若確定系統中都是透過commons-logging並未直接
呼叫log4j的話可以不用加此設定-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>log4j-over-slf4j</artifactId>
	<version>1.5.8</version>
	<type>jar</type>
</dependency>

(2)logback-test.xml 與 logback.xml
Logback預設會先找classpath下是否有logback-test.xml,若沒有的話再找logback.xml,若都沒有就用預設的configuration.
所以如果是採用Maven預設的Source Code Structure的話,只要在src/test/resources/下放一個test專用的logback-test.xml就可以專門記錄test產生log.而不需要特別再去改正常系統的logback.xml.

(3)debug mode與automatically reloading
Logback有個機制可以檢視系統載入的logback configuration,還可以定時確認logback.xml是否有被改變而重新載入改變後的設定

<configuration debug="true" scan="true" scanPeriod="30 seconds">
</configuration>
其中debug="true"就是開啟debug mode,會列出目前載入設定檔的名稱,裡面的logger,appender也會列出來。
而scan="true"就是啟用automatically reloading,scanPeriod則可以設定每隔多久檢查是否有更改而載入的時間。

(4)可以設定變數
1. 直接指定Properties name and value.

<property name="USER_HOME" value="/home/elliot" />
2. 利用file指定properties file location
<property file="src/main/resources/system.properties" />
3. 使用resource在classpath中找properties file
<property resource="system.properties" />
就可以在logback.xml中使用${USER_HOME}來控制Log

(5)RollingFileAppender supports automatic file compression。
只要用FixedWindowRollingPolicy或TimeBasedRollingPolicy就可以自動壓縮。

<FileNamePattern>${namepattern}.log.zip/.gz</FileNamePattern>
在FileNamePattern內最後加上.zip就會用zip壓縮,而加入gz即會使用gzip壓縮log.

(6)有趣的Filter
1. 可以利用LevelFilter只接收單一種類Level的Log

<filter class="ch.qos.logback.classic.filter.LevelFilter">
	<level>ERROR</level>
	<onMatch>ACCEPT</onMatch>
	<onMismatch>DENY</onMismatch>
</filter>
這個Filter相當方便,有時在DEBUG時只希望看ERROR的部份,這個Filter可以讓我專注於ERROR的資料。
2. 利用EvaluatorFilter接收含有特別意義的Log
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
	<evaluator name="myEval">
		<expression>message.contains("billing")</expression>
	</evaluator>
	<OnMismatch>NEUTRAL</OnMismatch>
	<OnMatch>DENY</OnMatch>
</filter>
這個Filter也相當有用,當我希望取得具有特定字串或Exception的Log時,這個Filter能很方便的取得需要的資料。

17 7月 2009

不要舉報我

西斯版為什麼好笑?請見範例,現在還是看一遍笑一遍啊

-----------------------------------

作者: ohyeahhh (古大熙) 看板: sex

標題: [心得] 近來西斯版的文章
時間: Tue Jun 9 21:18:37 2009
現在我依最近西斯版回文較多的文章題目,來後以各板可能的推文來加以分析
如有不同意或不正確之處,還請各位板友不吝嗇指正


[討論] 如果強暴罪最重可求處死刑...

Joke →:笑點勒 幹你娘 我走錯板了嗎
Boy-Girl →:愛不是這樣的,怎麼會有人在沒有愛的情況下還可以發生這種事
法西斯 →:那些賤男人,最好通通都給老娘我去死一死
西斯板 →:改判肛刑,讓牠們知道被捅的滋味,五樓你說好嗎
→:五樓都跟士官長肛肛好了,他沒再怕
→:電梯向下


[認真]女生在床上的時候,該叫些什麼

Joke →:笑點勒 幹你娘 是不會去問版喔
Boy-Girl →:心靈上的契合,即使沒有言語上的交流,也可以很完美唷
法西斯 →:叫甚麼不一定啦,但我男朋友就超喜歡我們在做那檔事的時候叫我稱讚他
→:推1F,適度地給男朋友鼓勵一下,真的能增加情趣
西斯板 →:你是我這輩子見過最大的男生
→:我聽了~~~我聽了~~~
→:邱若男,我要幹死你
→:歐歐歐歐 你是我的花朵
→:洽卡洽卡洽卡洽卡洽卡洽卡洽卡洽卡....咻咻~~~~
→:推文超好笑的啦XDDDDDDDDDDDDDDDDDD借轉就可
[m [32m※ [1m***** [;32;40m:轉錄至看板 joke [m


[心得] puma的特徵

Joke →:笑點勒 幹你娘 你媽知道你在這邊發廢文嗎
Boy-Girl →:說穿了,她們只是在愛情道路上迷途的羔羊,祝她們早日找到自己的真愛
法西斯 →:甚麼pu不pu,都是一群死阿宅追不到我們就愛叫我們puma,也不照照鏡子
→:對阿,就是有男生愛創出這種侮蔑我們女性的暱稱,是不是男生阿
西斯板 →:在各百貨公司8F體育專櫃出沒
→:內衣除了白色跟阿婆米色系列,其他顏色都可以在她們的衣櫃裡都找的到
→:在夜店看到歪國人就勃起的濃妝妹
→:推3F XDDDDDDDDDDDDDDD


[認真] 電愛習慣

Joke →:笑點勒 幹你娘 你捏捏自己的LP 這哪裡好笑
Boy-Girl →:我相信只要有心,雙方都肯花心思來經營,電愛也可以得到幸福
法西斯 →:很不切實際,我寧可努力上班工作或好好充實自己
西斯板 →:沒錢交馬子就算了,我連電愛的錢都沒有,越想越悶,去論壇繞一圈好了
→:樓上有股......


[討論] 女友信基督不給督

Joke →:笑點勒 幹你娘 有種不要刪
Boy-Girl →:可以雙方彼此先好好溝通,如果你是真心愛你女朋友,我相信你能體諒她
法西斯 →:當然不要給他們阿,他們有第一次就有第二次,我們要有堅持,感謝主
西斯板 →:基督教其實很Nice的,其中一定有甚麼誤會
→:主耶穌基督在你後面,他現在非常火
→:你可以跟她說其實你是耶穌轉世,射完記得說,阿阿阿阿阿阿阿阿阿門


[認真] 又見瑤瑤

Joke →:有乳必推 科科
Boy-Girl →:不懂你的問題點在哪,但還是祝你早日找到自己的真愛
法西斯 →:......
西斯板 →:阿宅,醒了沒
→:阿宅,醒了沒
→:阿宅,醒了沒
→:阿宅,醒了沒
→:阿宅,醒了沒
→:阿宅,醒了沒
→:========================反詐騙=========================


[認真] 男朋友最近都不碰我

Joke →:笑點勒 幹你娘 不要以為是女生就不噓你
Boy-Girl →:妳應該找個時間好好跟他談一談,看看妳們之間的問題點到底是甚麼
→:可能他是最近工作比較累,不要想太多啦,原PO加油
法西斯 →:一定是在外面有了,賤男人,通通去死死
西斯板 →:閃開!讓專業的來!
→:《私人信箱》有新進信件還沒看 鄉民衝了?
→:去找誠誠,車資他會出放心
→:妳應該趁現在好好試試鄉民的30cm
→:原PO是正妹


[認真] 我每次看到補習班的櫃台小姐就會勃起 這樣正常嗎

Joke →:笑點勒 幹你娘 阿阿阿阿阿阿阿阿阿阿阿阿
Boy-Girl →:你們年紀會差很多嗎,其實年齡也不是問題啦,只要肯用心經營
→:其實不太建議差太多歲的愛情啦,但事情也沒有說一定,原PO加油
法西斯 →:噁心死了,要問這種低俗的問題不會去西斯板問喔
西斯板 →:不正常,請砍掉重練
→:幹,圖哩
→:發文不附圖,此風不可長


[閒聊] 趁家人不在家 推砲~~

Joke →:笑點哩 幹你娘 趕閃我 噓死你
Boy-Girl →:你們真幸福 哈哈 要一直幸福下去喔
法西斯 →:記得一定要叫男朋友帶套喔
西斯板 →:你跟士官長都休假啦?
→:他老爸在門外打槍,他非常火
→:      還 蠻 屌 的
------

Jizz魂

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 123.240.224.19

碎碎唸(7)

以往下了班就是隨便買點東西,開了Windows桌機就等WOW的登入畫面(我的WOW是放在Windows的啟動....羞)。
現在呢,下了班也是隨便買點東西,開了一台Ubuntu的桌機、一台Ubuntu的筆電跟一台Mac mini,然後就是LPIC跟Ruby交替看著,Mac mini就乖乖當著動物機跑。那這些有什麼好碎碎唸?

Ubuntu 9.04支援ext4,實在是頗快啊!而且常用到的Apache2, Tomcat6, Subversion 1.5.4,要設定的東西實在愈來愈少,東西做這麼好,我以後離不開怎麼辦,公司裡那台Red Hat Server實在想丟掉啊。

從開始用Ubuntu當Server,不再單純只當Coding的開發機,發現自己有很多的錯誤觀念,沒事自己在自己home folder建個java 目錄幹什麼,tomcat跟maven不用Ubuntu綁定的話就下載後丟到/opt下啊,沒事在.profile裡加PATH幹什麼,直接用ln -s加到/usr/bin下啊。Ubuntu要求一定要用sudo來做這些事其實很不錯,可以讓自己想清楚權限的事,Red Hat搞到最後幾乎都用root登入,實在很糟糕啊(是我糟糕不是Red Hat)。

其他要唸的像是:

Valen Hsu的新專輯有點給他失望,雖說不是第一次失望,但之前那首單曲“好聽“實在不錯啊,總覺得後面2張專輯詞曲都不是很優。真想聽Valen唱唱郭靜的“心牆“…倒底最近還有什麼新專輯可以聽的?

Springframework 3停在M3很久了,說好的RC呢?已經延了一個多月了耶,是不是要喝下每朝啊?不然M這麼久也該看醫生吧。

西斯不西斯很久了,快點開版啊!鄉民快不行了吧!

2台Ubuntu,1台Mac mini,那…我那台比前面3台加起來總價還貴的MBP呢?有了iPod Touch,我會沒事開它來聽音樂嗎(誤)?

最後
Elliot@iPhone coming soon!

15 7月 2009

Maven:Properties

Maven:Properties 本篇是參考MavenPropertiesGuide整理的
Maven在POM中可以用的Properties大約可以分為下列幾種
(1)Build in Properties
${basedir}:取得mvn執行時pom.xml的所在目錄
(2)Project Properties
基本上pom.xml中所有的tag都是算在這類,只要加上project這個prefix即可。
${project.name}:可以拿到<name>yourprojectname</name>中的yourprojectname。
${project.version}:可以拿到<version>buildversion</version>中的buildversion。
${project.build.directory}:可以拿到<build><directory>builddirectory</directory></build>中的builddirectory。
而要取得parent的pom.xml資訊,只要將prefix改為parent.project即可。
(3)System Environment Variables
使用env這個prefix,可以取得系統中的變數。
基本上,在console下打env,顯示出的變數只要加上env.這個“prefix“,就能在pom.xml中使用。
${env.M2_HOME}:可以取得Maven的安裝目錄
${env.CLICOLOR}:可以取得mac的terminal是否要顯示顏色。
(4)Java Environment Properties
請參考http://java.sun.com/javase/6/docs/api/java/lang/System.html#getProperties(),其中所有的Key都可以被pom.xml使用。
比較有機會用到的像是
${os.name}:可以知道系統用的OS為何。
${file.separator}:目錄的分隔符號。

要知道這些Properties到底是什麼值其實也有點麻煩,如果沒在pom.xml裡執行也不能確定到底是什麼,但是Maven本身也沒有提供任何方式可以顯示這些Properties。
所以只好利用Antrun中執行echo這task來顯示囉,這是我最直接能想到的,如果有更好的方法也請不吝告知。
在pom.xml中上加
<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-antrun-plugin</artifactId>
			<version>1.3</version>
			<executions>
				<execution>
					<phase>initialize</phase>
					<configuration>
						<tasks>
							<echo>basedir:${basedir}</echo>
							<echo>project.name:${project.name}</echo>
							<echo>project.version:${project.version}</echo>
							<echo>project.packaging:${project.packaging}</echo>
							<echo>project.build.finalName:${project.build.finalName}</echo>
							<echo>project.build.directory:${project.build.directory}</echo>
							<echo>project.build.outputDirectory:${project.build.outputDirectory}</echo>
							<echo>env.M2_HOME:${env.M2_HOME}</echo>
							<echo>env.CLICOLOR:${env.CLICOLOR}</echo>
							<echo>settings.localRepository:${settings.localRepository}</echo>
							<echo>java.home:${java.home}</echo>
							<echo>java.version:${java.version}</echo>
							<echo>java.vendor:${java.vendor}</echo>
							<echo>os.name:${os.name}</echo>
							<echo>os.arch:${os.arch}</echo>
							<echo>os.version:${os.version}</echo>
						</tasks>
					</configuration>
					<goals>
						<goal>run</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>
自行修改<tasks>中的<echo> task成你要的,然後只要執行
>$ mvn initialize
就可以看到結果囉。

13 7月 2009

Maven: Create Eclipse Project

用Maven建立Eclipse Project其實頗為容易,第一步用plugin: archetype建立Maven Project,第二步再用plugin: eclipse建立Eclipse要用的設定檔,再來用Eclipse import即可。

1. run mvn archetype:generate
>$ mvn archetype:generate
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: local -> sampleweb-archetype (sampleweb-archetype)
2: internal -> appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)
.........
16: internal -> maven-archetype-quickstart ()
17: internal -> maven-archetype-site-simple (A simple site generation project)
18: internal -> maven-archetype-site (A more complex site project)
19: internal -> maven-archetype-webapp (A simple Java web application)
..........
41: internal -> gmaven-archetype-basic (Groovy basic archetype)
42: internal -> gmaven-archetype-mojo (Groovy mojo archetype)
Choose a number:  (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41/42) 16: : 

可以見到洋洋灑灑42個Template給你選,若沒合意的就用預設16來建吧。

[INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: checking for updates from central
Define value for groupId: : org.elliot.web
Define value for artifactId: : test
Define value for version:  1.0-SNAPSHOT: :
Define value for package:  org.elliot.web: :
Confirm properties configuration:
groupId: org.elliot.web
artifactId: test
version: 1.0-SNAPSHOT
package: org.elliot.web
Y: : y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating OldArchetype: maven-archetype-quickstart:RELEASE
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.elliot.web
[INFO] Parameter: packageName, Value: org.elliot.web
[INFO] Parameter: package, Value: org.elliot.web
[INFO] Parameter: artifactId, Value: test
[INFO] Parameter: basedir, Value: /Users/elliot/Documents/workspacetesting
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] OldArchetype created in dir: /Users/elliot/Documents/workspacetesting/test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

Maven要求你輸入groupId, artifactId, version, package後就會依你指定的artifactId建立一個Project。

2. run mvn eclipse:eclipse
進入該目錄後,執行mvn eclipse:eclipse
>$ cd test
>$mvn eclipse:eclipse
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'eclipse'.
[INFO] ------------------------------------------------------------------------
[INFO] Building test
[INFO]    task-segment: [eclipse:eclipse]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing eclipse:eclipse
[INFO] No goals needed for project - skipping
[INFO] [eclipse:eclipse {execution: default-cli}]
[INFO] Using as WTP server : null
[INFO] Adding default classpath contaigner: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] Using source status cache: /Users/elliot/Documents/workspacetesting/test/target/mvn-eclipse-cache.properties
[INFO] Not writing settings - defaults suffice
[INFO] Wrote Eclipse project for "test" to /Users/elliot/Documents/workspacetesting/test.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

再import至Eclipse即可

import import
3. 如果你有裝m2eclipse,那可以略過2改執行mvn eclipse:m2eclipse
>$ mvn eclipse:m2eclipse
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'eclipse'.
[INFO] ------------------------------------------------------------------------
[INFO] Building test
[INFO]    task-segment: [eclipse:m2eclipse]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing eclipse:m2eclipse
[INFO] No goals needed for project - skipping
[INFO] [eclipse:m2eclipse {execution: default-cli}]
[INFO] Using source status cache: /Users/elliot/Documents/workspacetesting/test/target/mvn-eclipse-cache.properties
[INFO] Using as WTP server : null
[INFO] Not writing settings - defaults suffice
[INFO] Wrote Eclipse project for "test" to /Users/elliot/Documents/workspacetesting/test.
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

一樣,import至Eclipse即可

import

使用Maven久了之後會發現,上列的方式仍有不便,例如Source Code Structure不符你的需求,相關的Plugin及Dependencies都需要一再加入pom.xml中,所以會希望能建立一個自己常用的範本。這時,你需要用的是archetype:create-from-project,然後將該archetype install到你Maven的repository中。簡單來說,用你現有的Project建立一個Template,之後再執行archetype:generate時再選擇你的template即可。

4. run mvn archetype:create-from-project
>$ mvn archetype:create-from-project
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building test
[INFO]    task-segment: [archetype:create-from-project] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:create-from-project
[INFO] ------------------------------------------------------------------------
[INFO] Building test
[INFO] ------------------------------------------------------------------------
[INFO] No goals needed for project - skipping
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:create-from-project {execution: default-cli}]
[INFO] Setting default groupId: org.elliot.web
[INFO] Setting default artifactId: test
[INFO] Setting default version: 1.0-SNAPSHOT
[INFO] Setting default package: org.elliot.web
[INFO] Archetype created in target/generated-sources/archetype
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

Maven會將archetype範本產生在target/generated-sources/archetype目錄下,如果還有需要可以進到該目錄,若沒問題的下可以進行下一步

5. run mvn install
先進入target/generated-sources/archetype後再執行mvn install
>$ cd target/generated-sources/archetype/
>$ mvn install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building test-archetype
[INFO]    task-segment: [install]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}]
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 7 resources
[INFO] [resources:testResources {execution: default-testResources}]
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/elliot/Documents/workspacetesting/test/target/generated-sources/archetype/src/test/resources
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:jar {execution: default-jar}]
[INFO] [archetype:add-archetype-metadata {execution: default-add-archetype-metadata}]
[INFO] [archetype:integration-test {execution: default-integration-test}]
[INFO] [install:install {execution: default-install}]
[INFO] Installing /Users/elliot/Documents/workspacetesting/test/target/generated-sources/archetype/target/test-archetype-1.0-SNAPSHOT.jar to /Users/elliot/.m2/repository/org/elliot/web/test-archetype/1.0-SNAPSHOT/test-archetype-1.0-SNAPSHOT.jar
[INFO] [archetype:update-local-catalog {execution: default-update-local-catalog}]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
6. run mvn archetype:generate -DarchetypeCatalog=local
再來就可以試者用自已的Template來建立Project了,不過這時要注意,由於Maven將你的Template加入local端的Catalog(存放 archetype的名稱),所以在run plugin:archetype:generate要加個參數指到local端的Catalog。
>$ mvn archetype:generate -DarchetypeCatalog=local
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: local -> sampleweb-archetype (sampleweb-archetype)
2: local -> test-archetype (test-archetype)
Choose a number:  (1/2): 

這時就能看到剛才加入的Template供選擇了囉!

Maven: Basic Concepts(Lifecycle, Phase, Goal)

Lifecycle / Phase / Goal
  • A build lifecycle is made up of phases.
    lifecycle將各phase有順序性的串連起來,所以當你指定執行一個phase時,maven將會執行排在其之前的所有phases.


  • A phase is made up of goals.
    一個Phase可以綁定多個Goals,但一般只有預設的一個Goal會被執行,所以要執行其他的Goal時,
    必需明白指出所要執行Goal。一般來說是以plugin:goal來表示,例如compile:test-compile


  • 說明下上面兩者的差別,例如test-compile這個phase,實際上是要執行compiler:testCompile,但是分別執行的結果如下
  • mvn test-compile
    >$ mvn test-compile
    [INFO] Scanning for projects...
    [INFO] ------------------------------------------------------------------------
    [INFO] Building Maven
    [INFO]    task-segment: [test-compile]
    [INFO] ------------------------------------------------------------------------
    [INFO] [resources:resources {execution: default-resources}]
    [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory /Users/elliot/Documents/workspacetesting/test/src/main/resources
    [INFO] [compiler:compile {execution: default-compile}]
    [INFO] No sources to compile
    [INFO] [resources:testResources {execution: default-testResources}]
    [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory /Users/elliot/Documents/workspacetesting/test/src/test/resources
    [INFO] [compiler:testCompile {execution: default-testCompile}]
    [INFO] No sources to compile
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    
    maven認出test-compile是一個Phase,所以執行了排在test-compile之前的Phase,
    如generate-resources、compile、generate-test-resource,最後在執行完test-compile
    (其實就是compiler:testCompile)後結束。



  • mvn compiler:testCompile
    >$ mvn compiler:testCompile
    [INFO] Scanning for projects...
    [INFO] ------------------------------------------------------------------------
    [INFO] Building Maven
    [INFO]    task-segment: [compiler:testCompile]
    [INFO] ------------------------------------------------------------------------
    [INFO] [compiler:testCompile {execution: default-cli}]
    [INFO] No sources to compile
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    
    
    Maven認出這是一個Goal所以只執行了compiler:testCompile就結束,並未執行其他的Goals。



  • Maven預設了三個Lifecycle ,各包涵了下列Phases.
    1. Clean Lifecycle
      • pre-clean
      • clean
      • post-clean
    2. Default Lifecycle
      • validate
      • initialize
      • generate-sources
      • process-sources
      • generate-resources
      • process-resources
      • compile
      • process-classes
      • generate-test-sources
      • process-test-sources
      • process-test-resources
      • test-compile
      • process-test-classes
      • test
      • prepare-package
      • package
      • pre-integration-test
      • integration-test
      • post-integration-test
      • verify
      • install
      • deploy
    3. Site Lifecycle
      • pre-site
      • site
      • post-site
      • site-deploy
    並不是所有的Phase都需要被執行,例如validate,在一般的情形下,單獨執行這個Phase會出現
    No goals needed for project - skipping而結束。
    而有些Phase會因設定的不同而執行不同的Goal,
    例如package,會因為你所設的packaging而執行war:war或jar:jar等不同的Goal。

    ECTO3 TEST

    Just test for ecto.

    continue edit



    08 7月 2009

    Development Tools on Mac

    習慣用的IDE當然是Eclipse啦,換個IDE就差不多變成癈人了,想當初從JBuilder換到Eclipse也是痛苦了很長一段時間,並不是IDEA或Netbeans不好,但是實在是沒什麼時間再習慣另一個IDE,除非Eclipse不再開發了,要不應該會一直用下去吧。
    用Eclipse當然要加些Plugin:
    MyEclipse:早期我一定要用的是MyEclipse,不過實在愈來愈肥,而且更新速度愈來愈慢(跟Eclipse更速度來比),所以在Ganymede之後就沒再用了,單純用Eclipse JEE的版本倒也頗為愉快。
    m2eclipse: http://m2eclipse.codehaus.org/,現在如果少了這個Plugin,我也算是個癈人了,Build、Test、Package都要靠Maven,在IDE裡可以快速執行Maven非這個Plugin不可。
    Subversive: http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/,在Windows的話首選應該是Sublipse,但是在Mac裡,Eclipse內建的Subversive也算是不錯了,而且更新速度跟得上Eclipse的改版,所以在Mac裡我都是用Subversive來跟SVN接。
    SpringIDE: http://dist.springframework.org/release/IDE,沒有Spring,那還能做案子嗎?有了這Plugin,在寫Spring 設定XML時方便多了,再也不用記Class裡有哪些field,其它設定檔裡有哪些Bean。
    Yourkit: http://www.yourkit.com/download/yourkit80_eclipse34/,這東西本身是要錢的,單下Plugin沒用,方便看程式裡Thread、Memory、Instance、Exception等各項資訊,主要是怕有Thread deadlock,Memory leak的問題,有這工具方便多了。Performance 倒不是我特別在意的。
    Properties Editor: http://propedit.sourceforge.jp/eclipse/updates/,多語系Properties files的編寫工具,我可不想再回頭用console來編,雖說Jinto也很不錯,但它相容性較差是我放棄的主因。
    再來跟DB有關的Client,我多是用Navicat,因為主要使用的DB不是Oracle就是Mysql,免費的Navicat lite 已經差不多夠了,Eclipse 中雖然有內建的DB Explorer,但說實話,實在不好用…
    寫這些其實・・・只是為了記Plugin的URL啦

    26 6月 2009

    Eclipse 3.5 (Galileo) for Mac:Carbon or Cocoa?

    Eclipse 3.5 (Galileo)如期在6月24日上線了,根據列出來的Support Platform來看真是相當浩大...比較引起Mac用戶注意的,應該是這次產品線開始支援32/64 bit Cocoa,但是困惑的是,倒底要選Carbon或是Cocoa的版本呢?

    非常無聊的我,兩個都下載來用看看(...10M光世代還不錯),發現:
    (1)兩個介面幾乎一樣,有差異的太少,比較明顯的是Cocoa用到SWT Sheet的部份,但真的是不多,另一個比較明顯的是Cocoa在元件間隔的使用上似乎比較有效率(忘了cut圖..),不清楚的話,選"About Eclipse Platform",比較兩者安裝模組按鈕上的差異,很明顯的發現,Carbon的版本,按鈕間隔出奇的大....這,算[無用]吧
    (2)兩者需要的環境一樣,Carbon雖然是比較舊的API環境,但兩者所需的都是"Apple Java for Mac OS X 10.5, Update 1",代表Carbon的版本並沒有比較好的向下相容性。
    (3)實在沒有太大差別...(記得某大師說,凡列舉一定要列至少三項,如果找不出第三項,就重覆強調前面二項...)

    所以看來用Cocoa或是Carbon沒有太大差別了?以支援度來說,Carbon應該是不會再有什麼發展了,但Cocoa會繼續走下去,雖說Cocoa可能對Java的支援度會降低,但SWT基本上在未來還是會包在Cocoa之上,出了問題被修正的機會跟速度都會比較快,而且有64 bit的Cocoa版本,無論如何都想用64 bit Java的朋友可以挑戰下自己的耐性。

    那我呢?裝完之後....就回去繼續用Ubuntu上的x86_64版本了

    Apple還我一個完整JDK6的環境啦!(翻桌

    22 6月 2009

    碎碎唸(6)

    離上一次登入WOW已經整整一個月了,雖然偶爾會連上Armory看看之前同團成員的資料,從成就裡還是可以瞭解些他們現在的情形,說不上是關心,也許只是淡淡的懷念吧,昨天發現有幾個人已經接近一個星期沒登入過,而奧杜亞成就也只停在威斯札,優格還沒倒,忽然有些難過....

    玩WOW讓我現實世界中大部份的事物都停滯不前,唯獨體重緩慢增加,雖說現在的公司沒有健身房,家裡附近沒有合適的場所可以運動也是個因素,但我想我花了太多時間在WOW上面還是主因,從2007年3月到今年年初,大約增加了14、15公斤。年初的健檢的確讓我嚇一跳,77公斤對於一個身高只有168、169的人來說是太重了些...控制飲食是有些效果,減到68、69左右卻又停了下來,突然覺得目標60公斤是好遠好遠的距離...想找出問題還是需要些記錄吧,從App Store 下載了Health Cubby,準備開始仔細地記記,也有個工具可以提醒自己....

    找Health Cubby時也想說順便找下記帳用的軟體,雖說我好像沒有透支的問題,上家公司薪水戶頭裡的錢買完高雄的房子都還有剩,依我花錢的方式來看,可能還能用個2年,只是想試試看記段時間,也許有什麼特別的發現;找了幾個軟體,覺得Balance太簡單,而其他又幾乎是要收費的,雖說USD $5、6不是很貴,但心理莫明有個聲音:暗、我也是寫軟體的....

    你總是藉黃昏隱沒

    ------------------------------------------------------------------------------

    【我們甚至失去了黃昏】 聶魯達著/李宗榮譯

    我們甚至失去了黃昏的顏色。
    當藍色的夜墜落在世界時,
    沒人看見我們手牽著手。

    從我的窗戶中我已經看見
    在遙遠的山頂上落日的祭典。

    有時候一片太陽
    在我的雙掌間如硬幣燃燒。

    在你熟知我的哀傷中
    我憶及了你,靈魂肅歛。

    彼時,你在哪裡呢?
    那裡還有些什麼人?
    說些什麼?
    為什麼當我哀傷且感覺到你遠離時,
    全部的愛會突如其然的來臨呢?

    暮色中如常發生的,書本掉落了下來,
    我的披肩像受傷的小狗踡躺在腳邊。

    總是如此,朝暮色抹去雕像的方向
    你總是藉黃昏隱沒。

    ------------------------------------------------------------------------------

    我想這是最令人傷感的夕陽了
    只因為它
    落在我望著你離去的窗口

    17 6月 2009

    你不像任何人

    ------------------------------------------------------------------------------

    【每日妳與宇宙的光...】 聶魯達著/李宗榮譯

    每日你與宇宙的光一起嬉戲。
    靈巧的訪者,在花朵與水之間你翩然到訪。
    你比我手中緊握的白色的頭顱,
    更像每日我手中的成簇的果實。

    你不像任何人,因為我愛你。
    讓我把你灑在眾多花圈之中。
    誰在南方群星裡,以煙的字母寫下你的名字?
    喔,在你存在之前,讓我憶起你往日的樣子。

    突然地,風在我緊閉的窗上怒嚎狂擊。
    天空是一張網,塞滿了陰暗的魚。
    全部的風在這裡逐一釋放。全部。
    大雨脫去她的衣服。

    眾鳥飛逝,逃離。
    風,風。
    我只能與男人的力量相互搏鬥。
    暴風雨讓黑色的樹葉迴旋飄落,
    讓昨夜停泊在天空的船隻逐一散落。

    你在這裡。喔,你並沒有離開。
    你會回應我直到我最後一個祈求。
    好像受驚嚇般的緊擁住我。
    即使如此,一抹詭異的影子仍掠過你的雙眼。

    現在,現在也是,小親親,你帶給我忍冬樹,
    甚至你的胸部都可聞到它的味道。
    當哀傷的風開始屠殺蝶群,
    我愛你,而且我的幸福啃噬你的梅子的嘴。

    你為何非要因順應我而委屈受苦﹖
    我孤獨與狂野的靈魂,我的釋放它們奔跑的名字。
    我們曾看見晨星燃燒這麼多次,並親吻我們的雙眼,
    在我們的頭頂上,薄暮在旋轉的風扇中逸散。

    我的話語像大雨淋在你的身上,輕撫你。
    許久以來,我愛上你陽光曬過的珍珠母的身體。
    我甚至於相信你擁有整個宇宙。
    從群山中我將為妳捎來幸福的花束、風鈴草,
    黑榛樹的果實,以及一籃籃的吻。

    我要
    像春天對待櫻桃樹那樣的對待你。

    ------------------------------------------------------------------------------

    你不同於任何人,因為我愛你。
    我在這寫下無法對你說出口的言語,只能期待許久之後,可以漂到你手中。

    Es tan corto el amor, y es tan largo el olvido.

    知道Pablo Neruda,最初是因為紅膠囊,封面的圖吸引了我拿起它,李宗榮譯的"二十首情詩與絕望的歌";後來有很長一段時間,這本書擺在我書桌旁最容拿到的位置,裡面每一首詩,對我而言似乎都有著說不完的故事。

    年紀大了後才明白,所有的故事都應該要有結局。

    這本書逐漸被我放逐,停在Dissecting MFC 2nd Edition的旁邊,似乎不會再回來了。

    而現在,我是用什麼樣的心情再拾起它?

    Love may end soon, but memory won't.

    我只是逃避,但未曾放下。

    "愛情太短,而遺忘太長。"

    13 6月 2009

    碎碎唸(5)

    最近常常突然就進入放空狀態...慘。

    不過也不是完全沒收獲,發現了幾首放空時聽了卻完全不會干擾到放空狀態的歌。

    青山黛瑪 - そばにいるね

     

    梁靜茹-可惜不是你

     

    剛剛在PTT看到一篇評魔羯座的,其中有一句

    "如果他愛你,你就什麼都不用做,因為他都會幫你做;如果他不愛你.你也什麼都不用做,因為做了也沒用"

    我笑了起來

    繼續放空....

    12 6月 2009

    Eclipse 3.5 RC3 Released

    之前沒什麼注意,不知不覺Eclipse 3.5(Galileo)已經到了RC3的階段了,看Schedule預定是在2009/06/24要發正式版!依以往的慣例,到了RC3差不多就很接近正式版了,API應該不會再改,會再修的只有BUG了,無聊之餘也就看看有什麼新東西,沒想到有幾項新功能真的是要給他稱讚一下。

    (1)There is a new toString() generator

    之前如果不掛個commons4e的Plugin那就用org.apache.commons.lang.builder.ToStringBuilder來override toString() method,缺點是前者要錢,後者則會破壞pure的dependency 按Alt+Shift+S,選取"Generate toString()"

    選取用來產生String的fields

    輕鬆產生 toString() method

    (2)There are several enhancements to the Compare Editor Menu裡多個了"Compare With"的選項

    可以選取Local端的記錄

    Compare Editor就出現囉

    (3)The Javadoc view and hovers now support the {@inheritDoc} tag and add links to overridden methods 只要在被Override的部份加上{@inheritDoc} tag,就以少寫點註釋...也可以少番點Javadoc了

    (4)The JUnit4 version shipped with Eclipse has been updated to 4.5 雖然不錯,但是有用到Spring Test的要看一下Jira裡回報的問題 Spring TestContext Framework not compatible with JUnit 4.5

    11 6月 2009

    碎碎唸(4)

    睡不著,拿起了村上春樹的"國境之南、太陽之西"複習,這本小說是我第一次接觸村上成為村上迷的開始。手上這本是1998年2月第16刷,也就是這本書大約在我身邊已經過了10年了,所以我記憶應該沒錯,是我在新化受預官訓時放假等車回家,頗為無聊時在書店翻起,在村上之前我所知道的日本作家,大概就是夏木漱石、大江健三郎、川端康成這些作家,對村上的印象頗淺;依我的習慣,通常不太熟的作家我都是先看略薄一點的著作,如果看完有興趣,就會將該作家的書全部掃完(這真的應該算病態吧...)。

    那時挑這本書沒什麼原因,只是因為它比較薄,封面截錄的" '萬物都在那裡生長',你說,'然而真正存活的只有沙漠本身' ",其實引不起我的興趣....從台南回台北的路程很長,時間充足到可以讀這本書2遍,下了車,我沒有先回家,而是先到重慶南路再掃了幾本村上的書。

    村上小說的主角,通常都是相當普通的人,就像是週遭就能見到的,而不是難以觸及的菁英份子或俊男美女,故事的內容會讓我產生莫名的認同感,似乎在說的不是別人而是自己的故事,就是這樣的認同感,讓我讀著一本又一本,一遍又一遍。

    "我常常讀書、聽音樂。....一旦開始讀起來,中途都欲罷不能。那對我來說好像是麻藥一樣的東西。...只要一有時間就窩在房間裡聽爵士唱片。...但是幾乎沒有欲望把我那種讀書和聽音樂的體驗和別人談論。我就是我自己,不是其他任何人,這反而使我感到安逸、滿足。在這層意義上,我是一個極端孤獨而傲慢的少年。",這是描寫主角始在高中時的心境,怎麼看都覺得跟年輕的自己好像。

    如果是島本的話,或者是泉的話,我就可以比較正確地表達的心情。....我想如果真的能這樣的,不知道該有多好。可是我並沒有做任何努力去實現這想法。結果她們只是已經從我的人生之中失去的存在。時鐘是不能逆轉的。”,“島本,最大的問題是我欠缺了什麼。我這樣一個人,我的人生,空空的缺少了什麼,失去了什麼,而那部份一直飢餓著,乾渴著。....這個世界上只有妳一個人能夠做到這個。跟妳在一起,我才感覺到那個部份滿足了。....我再也沒辦法回到那樣的世界去了。”。

    其實不是沒有話要說的,只是自己的故事,沒有必要讓每一個人都知道,只要有那個人聽我說就好,除了那個人之外的其他人我都不在乎,這樣的想法,已經不知道在我心裡浮現多少次。如果那個人還在,我應該與現在有很大不同吧,每次拿起這本小說,總是抱著可以捨棄一切只求能再見她一面的想法,但畢竟是不可能的事了....

    非常遺憾的是,某些事物是不能往後退的。那一旦往前走之後,不管怎麼努力,都回不去了。如果那時候有什麼絲毫差錯的話,就會以錯誤的樣子凝固下來。”

    我在這裡,唯一能做的,就只是回憶而已。

    10 6月 2009

    因為風的緣故

    ------------------------------------------------------------------------------
    【因為風的緣故】  洛夫

    昨日我沿著河岸
    漫步到
    蘆葦彎腰喝水的地方
    順便請煙囪
    在天空為我寫一封長長的信
    潦是潦草了些
    而我的心意
    則明亮亦如你窗前的燭光
    稍有曖昧之處
    勢所難免
    因為風的緣故

    此信你能否看懂並不重要
    重要的是
    你務必在雛菊尚未全部凋零之前
    趕快發怒,或者發笑
    趕快從箱子裡找出我那件薄衫子
    趕快對鏡梳你那又黑又柔的嫵媚
    然後以整生的愛
    點燃一盞燈
    我是火
    隨時可能熄滅
    因為風的緣故
    ------------------------------------------------------------------------------

    其實,我也不明白,為什麼抓住我心的,都是我不懂的東西。

    專案心得

    這個案子相對以前其他的案子,規模小上一截,所以很大膽地使用了Struts2到案子裡來,隨著開發逐漸看到當初在寫Demo沒想到的問題,而且將舊時常用的JavaScript Library從Prototype改成jQuery,大量使用Ajax來處理Data與Form Submition,而這些也改變了不少舊有Demo的Operation Pattern,中間也就累積了不少新筆記,等再空一些整理一下,有不少是蠻有趣的值得一看的東西,就數量來說的確是不少,應該可以當本小書了。

    先舉個例來說,以往的分頁查詢(pagination search)模式在Action除了宣告一個domain object做為 search example來記錄使用者在Search Form輸入的條件,還會直接宣告一個int pageNo = 1;這樣每次在Search顯示Result時,可以直接將使用者輸出的舊有條件顯示出來,並將pageNo直接改為1,這樣再按下查詢钮時就直接以使用者輸入條件查詢並顯示結果中的第一頁,但改用Ajax來處理Form Submition,查詢用的Form跟pageNo根本不會也不需要被更新(我是在按下pagination 的頁碼再按form的search button才發現pageNo沒更新帶來的問題...算笨到),所以處理模式會有些小小的差異,諸如此類的東西不少,看起來重要性不高,但這些帶出來我對於Action Layer有新的想法,能少幾行Code就少幾行,嗯...整理整理。

    這個案子真的一行"SQL"都沒寫,算是Hibernate完全利用吧(人懶就承認好了...),希望還有這樣的小案子,可以慢慢地實驗我的新想法。Spring 3應該不遠了,Maven 2.1跟之前2.0.x也有著不少差異...哪裡找案子來當實驗品呢?

    08 6月 2009

    眾荷喧嘩

    ------------------------------------------------------------------------------

    【眾荷喧嘩】  洛夫

    眾荷喧嘩
    而你是挨我最近
    最靜,最最溫婉的一朵

    要看,就看荷去吧

    我就喜歡看你撐著一把碧油傘
    從水中升起
    我向池心
    輕輕扔過去一拉石子
    一隻水鳥
    如火焰般掠過對岸的柳枝
    再靠近一些
    只要再靠我近一點
    便可聽到
    水珠在你掌心滴溜溜地轉
    你的臉
    便嘩然紅了起來

    你是喧嘩的荷池中
    一朵最最安靜的
    夕陽
    蟬鳴依舊
    依舊如你獨立眾荷中時的寂寂

    我走了,走了一半又停住
    等你
    等你輕聲喚我

    ------------------------------------------------------------------------------

     

    也許,我不該走的

    碎碎唸(3)--說是心得太沉重

    又是碎碎唸?因為說是心得太沉重...

    白石一文在台有翻譯出版的小說應該都看完了吧?一瞬之光、我心中尚未崩壞的部分、愛有多少、永遠在身邊、心中鑲著龍。白石一文的小說果然口味比較重,沒一本看完開心的...

    不能分割的生與死,中間的日子要如何渡過?將每一刻都當做最後一刻來過,致力將其成為最閃耀的極致時光,生氣蓬勃地活著走向死亡,在其他生命的幸福裡認可自己的生命?孕育一個生命就是將他推向死亡,人無法選擇自己的出生與否,甚至也無法選擇自己的死亡方式,這樣的生命,如果只是受著看不見的命運與不斷浮現的慾望控制而活動,又怎麼能明確定出"自我"的存在與意義?也許"一瞬之光"跟"我心中尚未崩壞的部分"要合在一起看。

    眼裡所見的,終究只是事實其中一部份;"所謂的理解,通常只不過是誤解的總合"。愛有多少這本書裡提到的四個故事,都在說明"肉眼不可見的確定性",無論是岬與安西一開始的誤解,市川家與里見家複雜的親子關係、知佳與英一的外遇、正平與晶交往的問題,都受著當事人看不見的事物所影響,只是...當眼前所見都不能完全相信時,還能相信些什麼呢?

    有沒有年過30淚腺比較不容易控制的八掛?為什麼我看完岬寫的"致廿年後的我"居然流淚到眼紅而看不下書?而岬所想的,尋找心愛的人與尋找可以成為妻子的人其中的區別,是其無法判斷能否發自內心愛對方的底線,我也只能如搗蒜般地點頭,"所見即所思",等等...我很確定我是男人...

    至於心中鑲著龍,實在很難從書名想像內容,看到封面就更糟糕了...看完了的感想是完全屬於黑暗面的,人際關係陰沉面的回憶成為我腦海裡揮之不去的困擾,基於散播憂傷是不道德的行為,當我沒提過...

    沒有生命的事物才能永遠在一起,就如同故事裡兩個主角小時候所立下刻著名字的石磚,人生的際遇終究無法預測,你所得到的並不一定是你所追求的,更多的是不請自來的,津田敦最後在醫院裡對青野精一郎發洩的他對於人生的憤怒與不甘願,的確說出了生命的無奈與悲哀,但是精一郎的回覆也有意思,"大家都很努力活著,這樣就足夠了",不需要對發生在別人身上的遭遇覺得有必要負起責任,每個人都有追求幸福的權利,但為了別人幸福而犠牲自己則大可不必。也許,簡單的說,不要把別人的人生扛在自己的肩上,只要大家都努力地活著,這樣,就好。(我也不確定我在寫什麼,也許該解構一下....),我難以完全體會表達的原因,也許是因為像是十多歲時聽李宗盛的凡人歌,少了點閱歷吧。

    07 6月 2009

    碎碎唸(2)

    原諒我自己將以非常零碎而雜亂的方法記事,不然可能悶很久也沒什麼東西出來...

    工作是簡單的:

    • 發現問題,分析目前可見已發生的現象,推測可能發生的原因,找出可能的解決方式,將其解構為執行的步驟,驗証問題是否消失,於是所有的可能都變成確定。
    • 提出構想,分析手上現有的資源,推演是否能完成,再加以分項執行,找合適的人,建立確認點,再想下一個構想。

    之所以稱為簡單,是因為已經有可見的結果,所以該如何走,是否已經走到都可以被確認,也許路不一定好走,但總體上來說還是比較簡單的,至少是可以理解而不會困惑的。就像迷宮是簡單的,只要從出口倒回去走,就能在花費最短時間的情形下找到正確的路。

    現實中,大部份的問題並沒有明確的答案。選擇會決定事情的結果,但當下並不能看到那個結果。可以有所期望,但是失望的機率永遠存在。這是因為我們沒辦法看得到所有的現象,所以完整無誤的執行步驟是難以被建立的。而即使我們找到可能的方式,也因為問題難以再次完整重現,而不能確定所做的方式是正確的。

    正確性與絕對性,在大部份的事實中,並不存在。

    我們所看到的"事實",通常只是"它"其中的一面,還有很多是我們看不到的。人也是一樣,你以為你明白某個人,其實只是知道其中一面,還有很多的"他"是你沒見過的,即使見過,也不一定能明白。

    當有人對我說:"我明白你的感受"、"我瞭解你這個人",我可能會非常刻意地漏出嗤嗤的笑(鼻)聲,我常常都覺得不明白我自己了,為什麼有人可以用這種具有"絕對性"語意地方式來發表"正確性"的意見?

    "可能、也許、大概是",我的對答裡通常使用了大量的不確定語氣,不是因為想逃避或是不誠懇,我儘量對我的言語負責,但我實在難以違背我對絕對性的理解。

    如果我用了絕對性地語氣說話,可以不接受,但是請不要懷疑。

    例如:

    我 愛 你

    01 6月 2009

    碎碎唸(1)

    其實我的碎碎唸很多,只是不太想寫,不寫的話這個BLOG好像也沒什麼新東西,所以還是多少唸一下好了,也許接下來也來噗浪一下...

    不玩WOW了,這次不是帶著怨念離開的,所以應該是不會再回去,附上Armory,抓到有更新的話有賞(可惜了我身上那幾萬G)。

    時間多了很多出來(非常多!),所以只好找些東西消磨時光,暫時不想太認真看工作有關的,就找了幾本小說看了下去,先就幾個作家的作品各買一本回去看,覺得好就打算將該作家的作品買完(似乎也算是種病態?),結果不錯,發現了兩個很有趣的作家,一位是白石一文,另一位是恩田陸。

    白石一文先入手的是"一瞬之光",這本書剛出時就有略為翻過,只是我對菁英份子+俊男美女這種類型的故事並不是非常有興趣,所以也就沒再看下去,這次只是看到不少人推薦,再加上書本略為有些厚度,應該可以消耗些時間,沒想到也沒用到四小時就讀完...故事本身其實相當有意思,我不喜歡當地雷,有興趣的可以自行翻翻。感想?當然有: 一個不愛自己的人,其實也沒辦法完整地愛人;一個不清楚自己要什麼的,也無法瞭解別人要的是什麼。與其說這是感想,不如說是印證....

    恩田陸先入手的是"夜間遠足",整本書讀起來溫暖而誠懇,完全讓我回到十多歲時的青少年心態,故事在步行間逐漸察覺自己心裡的聲音與週遭朋友傳來的溫暖情誼,真希望自己也是書裡人物的一份子,陪著大家一起走下去....

    這幾天在博客來花的錢已經超過4000元,差不多可以玩WOW一年了,但是覺得很值得,非常值得!!!好像回到十多歲時,拼著命抓時間讀跟課業完全無關的讀物;雖說青春不能重來,但是這種找到真正的自己的感覺,已經很久很久不曾經歷了(我在說什麼?其實我也不完全清楚....)

    植物園的荷花應該開滿了吧?也該找時間去看看了,有人要一起的嗎?

    PS:很明顯,我敍事跟表達的能力大約只有從前國中的程度(不是因為夜間遠足...)

    10 4月 2009

    Compass Configurations of Spring

    專案中要用到全文檢索的功能,  從Lucene開始看起, 後來發現Compass, Compass將Lucene底層封裝後來使用, 而且可以配合Hibernate跟Spring, 可以直接在Hibernate更新資料時一併處理index, 比直接使用Lucene要方便得多, 只是資料實在不算多, 而且不少資料是較舊的, 花了不少時間在試, 當然要記一下囉! 不過只記設定方式, 相關用法....懶, 有機會再整理筆記好了...

    一、Maven Dependencies

    <!--Search Engine-->
    <dependency>
     <groupId>org.compass-project</groupId>
     <artifactId>compass</artifactId>
     <version>2.1.3</version>
    </dependency>
    <dependency>
     <groupId>org.apache.lucene</groupId>
     <artifactId>lucene-core</artifactId>
     <version>2.4.1</version>
    </dependency>
    <dependency>
     <groupId>org.apache.lucene</groupId>
     <artifactId>lucene-highlighter</artifactId>
     <version>2.4.1</version>
    </dependency>
    <dependency>
     <groupId>org.apache.lucene</groupId>
     <artifactId>lucene-analyzers</artifactId>
     <version>2.4.1</version>
    </dependency>
    <dependency>
     <groupId>org.apache.lucene</groupId>
     <artifactId>lucene-queries</artifactId>
     <version>2.4.1</version>
    </dependency>

    更新其實還蠻快的, Lucene一更新, Compass也隨即有新的對應版本, Maven中的dependency會用到大概就是這些.

    二、Spring Beans Configuration

    <bean id="annotationConfiguration"
      class="org.compass.annotations.config.CompassAnnotationsConfiguration" />
    <bean id="compass" class="org.compass.spring.LocalCompassBean">
     <!-- xml configuration mode 
     <property name="resourceLocations">
      <list>
       <value>classpath:your/domain/Entity.cmd.xml</value>
      </list>
     </property>
     -->
     <!-- anontaition mode -->
     <property name="classMappings">
      <list>
       <!--<value>your.domain.Entity</value>-->
      </list>
     </property>
     <property name="compassConfiguration" ref="annotationConfiguration" />
     <property name="compassSettings">
      <props>
       <prop key="compass.engine.connection">
        ${compass.engine.connection}</prop>
       <prop key="compass.transaction.factory">
        org.compass.spring.transaction.SpringSyncTransactionFactory</prop>
       <prop key="compass.engine.optimizer.aggressive.mergeFactor">0</prop>
       <prop key="compass.engine.analyzer.default.type">
        org.apache.lucene.analysis.cjk.CJKAnalyzer</prop>
      </props>
     </property>
     <property name="transactionManager" ref="transactionManager" />
    </bean>
    <bean id="hibernateGpsDevice" class="org.compass.gps.device.hibernate.HibernateGpsDevice">
     <property name="name" value="hibernateDevice" />
     <property name="sessionFactory" ref="sessionFactory" />
     <property name="nativeExtractor">
      <bean class="org.compass.spring.device.hibernate.SpringNativeHibernateExtractor" />
     </property>
    </bean>
    
    <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps"
     init-method="start" destroy-method="stop">
     <property name="compass" ref="compass" />
     <property name="gpsDevices">
      <list>
       <!--
       When using {SpringSyncTransactionFactory}, this gps device
       wrapper(SpringSyncTransactionGpsDeviceWrapper) should be used to 
       wrap all the devices
       -->
       <bean
        class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper">
        <property name="transactionManager" ref="transactionManager" />
        <property name="gpsDevice" ref="hibernateGpsDevice" />
       </bean>
      </list>
     </property>
    </bean>

    大部份都是制定的, 只有少數是可以讓你變動, 我的設定跟網路上其他可以找到的資料來比, 有差別的是hibernateGpsDevice跟compassGps.gpsDevices, hibernateGpsDevice用org.compass.gps.device.hibernate.HibernateGpsDevice是因為org.compass.spring.device.hibernate.SpringHibernate3GpsDevice在2.0M1時就設定為deprecated, 必需改用HibernateGpsDevice, 而gpsDevices使用org.compass.spring.device.SpringSyncTransactionGpsDeviceWrappe的原因在這Class的Javadoc中, 當使用SpringSyncTransactionFactory來管transaction時, 就要使用SpringSyncTransactionGpsDeviceWrapper將其他GPS Devices封裝.

    接下再透過cmd.xml或annotation來設定Searchable的Class跟Index properties後就可以很容易的操作了, Compass的reference文件相當清楚, 仔細讀過的話大部份問題都可以找到答案, 配合PDFBox跟POI等OSS, 還可以將PDF, Word, Excel, PowerPoint中的內容取出做為檢索資料, 完成一個簡單的全文檢索系統實在不費什麼力氣...

    14 1月 2009

    補遺

    有些東西做了後才發現仍有疏忽之處 Ubuntu: mysql5: root除了要加上“@%“以便可以在非本機的環境下登入操作,還有要修改"/etc/mysql/my.cnf",將"bind=address=127.0.0.1" 給mark掉才行。 tomcat6: 8.10直接用apt-get安裝就好,不用再自行安裝,設定檔在"/etc/tomcat6/"中,主程式則放在"/usr/share/tocmat6/"下 apache2: JkMount/JkUnmount要直接加在"/etc/apache2/sites-enabled"中要起用的VirtualHost裡,單獨加在"/etc/httpd.conf"是沒有用的 Spring 2.5: 新增的@Autowired跟@Qualifier可以合作的很好,在有多個同樣type的beans時,Qualifier可以指出你想要的那一個。 @Component不錯用,但@Transactional用在一般的就可能要考慮,以AOP設定可能是更好的選擇,但用在TestCase中加上@Rollback(true)對於簡化Test很有幫助

    Technorati Tags: ,