Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Monday, April 18, 2011

The classpath*: prefix of java

When constructing an XML-based application context, a location string may use the special classpath*: prefix:


ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");

This special prefix specifies that all classpath resources that match the given name must be obtained (internally, this essentially happens via a ClassLoader.getResources(...) call), and then merged to form the final application context definition.

Classpath*: portability
The wildcard classpath relies on the getResources() method of the underlying classloader. As most application servers nowadays supply their own classloader implementation, the behavior might differ especially when dealing with jar files. A simple test to check if classpath* works is to use the classloader to load a file from within a jar
on the classpath:

getClass().getClassLoader().getResources("someFileInsideTheJar").

Try this test with files that have the same name but are placed inside two different locations.
In case an inappropriate result is returned, check the application server documentation for settings that might affect the classloader behavior.

The "classpath*:" prefix can also be combined with a PathMatcher pattern in the rest of the location path, for example "classpath*:META-INF/*-beans.xml". In this case, the resolution strategy is fairly simple: a ClassLoader.getResources() call is used on the last non-wildcard path segment to get all the matching resources in the class loader hierarchy, and then off each resource the same PathMatcher resoltion strategy described above is used for the wildcard subpath.

Memo: This article content copied from spring 3.0 framework reference PDF file.

Friday, January 28, 2011

Tomcat URL 支持中文文件名

在tomcat的默认配置情况下,如果访问一个"中文.html"页面,服务器会抛出文件找不到的错误提示,这需要对tomcat的配置文件略作改动,为Connector设置URIEncoding的参数。
在server.xml文件中找到8080服务器配置的一段设置:

<Connector port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" debug="0" connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>


加上 URIEncoding="UTF-8" 这句就可以识别中文文件名了,同时如果url中的参数值有中文,服务器端也可以正常解析对应的参数,否则服务器端Java程序中取到的参数是以ISO-8859-1编码的,有中文字符的参数值是乱码的,加了URIEncoding="UTF-8"之后,就可以正确获取到参数值了。
对于这个参数的说明,可以查看tomcat目录中的doc帮助文件,也可以从官网中找到此参数的解释。

References: 官方文档
Configure tomcat's uri encoding

Sunday, December 19, 2010

spring的属性编辑器CustomDateEditor及日期对象转化

在spring mvc的Controller中,属性在通过依赖注入(DI)时,普通数据类型都能够辨识。但诸如Date之类,就需要自定义属性编辑器解决。否则报如下错误:
org.springframework.beans.TypeMismatchException:
Failed to convert property value of type [java.lang.String] to required type
[java.util.Date] for property 'date'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property 'date': no matching editors or conversion strategy found
这表示spring无法找到合适的转换策略,需要自己写一个转换器,在spring中称之为属性编辑器。
spring中的属性编辑器可以将字符串转换为相应的对象,然后注入到其它对象中去。
编写自己的属性编辑器的步骤很简单,属性编辑器类需要从java.beans.PropertyEditorSupport类继承,在这个类中有一个setAsText方法,这个方法有一个String类型的参数,通过这个方法,可以将String类型的参数值转换成其他类型的属性。在这个方法中我们还需要使用一个setValue方法,就来指定转换后的对象实例。
spring 中有个 CustomDateEditor 的类就是继承 PropertyEditorSupport 的一个属性编辑器,在Controller中添加一个@InitBinder的Annotation到某个方法上,在方法中指明日期字符串的格式,就可以将符合此格式的字符串转化为日期对象,代码如下:


/**
* <pre>
* HTML forms work with string values only, when your Authority is a complex bean. You need to configure a PropertyEditor to perform conversion between Authority and String:
*
* @InitBinder
* public void initBinder(WebDataBinder b) {
* b.registerCustomEditor(Authority.class, new AuthorityEditor());
* }
*
* private class AuthorityEditor extends PropertyEditorSupport {
* @Override
* public void setAsText(String text) throws IllegalArgumentException {
* // 另外一个例子是根据字符串,从数据库中查找返回对象
* setValue(authorityService.findById(Long.valueOf(text)));
* }
*
* @Override
* public String getAsText() {
* return ((Authority) getValue()).getId();
* }
* }
* </pre>
*
* 这个方法用来将页面表单上传的Date字符串转化成java的Date对象
*
* @param binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}


Reference: how to pass a date into bean property

Saturday, November 27, 2010

用maven来运行一个main方法或者启动Server

在maven项目的pom.xml文件的plugins中加入"exec-maven-plugin"这个插件,这个在运行"mvn package"时,会在当前的mvn进程中直接执行指定的class文件的main方法,也可以配置其他的参数,让此main在另一个java进程中启动。如果其中将phase的内容改为"test",就会在运行"mvn test"时执行main方法,也可以在命令行里直接用mvn运行,如下注释说明。
更详细的信息和配置方法,可参考http://mojo.codehaus.org/exec-maven-plugin/usage.html说明。

<!-- commandline: mvn exec:java -Dexec.mainClass="org.phpfirefly.test.Server" -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.phpfirefly.test.Server</mainClass>
</configuration>
</plugin>

maven2 repository server install

以下为安装免费版本的nexus maven2服务器和简单的设置过程:


$> wget http://nexus.sonatype.org/downloads/nexus-oss-webapp-1.8.0-bundle.tar.gz
$> tar zxvf nexus-oss-webapp-1.8.0-bundle.tar.gz
$> mv nexus-webapp-1.8.0-bundle /usr/local/nexus
$> cd /usr/local/nexus
$> ls bin/jsw/
$> bin/jsw/linux-x86-32/nexus start
$> tail -f logs/wrapper.log

启动服务后默认URL为:http://localhost:8081/nexus
默认的登录名和密码:admin/admin123
nexus默认是关闭远程索引下载功能的,主要是担心会造成对服务器的巨大负担,需要我们手工开启。
开启的方式: 点击Administration菜单下面的Repositories,将这4个仓库Apache Snapshots,Google code,Codehaus Snapshots,Maven Central的Configuration - Download Remote Indexes修改为true。然后在这三个仓库上分别右键,选择reIndex,这样Nexus就会去下载远程的索引文件。
部署构件至Nexus: Nexus提供了两种方式来部署构件,你可以从UI直接上传,也可以配置Maven部署构件,在上传一个版本时,可以将jar包和source jar包一起上传。

本地maven仓库配置文件,默认位置在用户根目录下的".m2"目录,文件名为settings.xml,如果没有,则创建一份,更新内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

<pluginGroups>
<!-- pluginGroup
| Specifies a further group identifier to use for plugin lookup.
<pluginGroup>com.your.plugins</pluginGroup>
-->
<pluginGroup>org.mortbay.jetty</pluginGroup>
</pluginGroups>

<profiles>
<profile>
<id>nexus</id>
<repositories>
<repository>
<id>nexus</id>
<name>local nexus</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>local nexus</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>nexus</activeProfile>
</activeProfiles>
</settings>

References: http://juvenshun.javaeye.com/blog/349534
http://wj98127.javaeye.com/blog/306358

Sunday, October 24, 2010

Scripting java using rhino and javascript

通过Rhino可以使javascript调用java的标准类库,这使得javascript的编程能力得以强化,在服务器端已经有javascript的MVC框架,一般也是基于Rhino的.
首先在ubuntu上可以通过命令安装rhino:
$> sudo apt-get install rhino

安装完成后,在命令行中输入js或者rhino:

$> js
$> rhino
Rhino 1.7 release 2 2010 09 15
js> new Date()
Sun Oct 24 2010 17:24:27 GMT+0800 (CST)
js> /^\d+$/.test("369");
true

就可以进入javascript的控制台.

另外一种方式就是从网上下载rhino 1.5R4.1版本,在命令行中用java运行,下面的代码在命令行的rhino1.7版本中不能运行,因为无法导入java.awt.*的包:
$> java -jar rhino-1.5R4.1.jar
Rhino 1.5 release 4.1 2003 04 21
js> importPackage(java.awt);
js> frame = new Frame("JavaScript")
js> frame.show()
js> button = new Button("OK")
js> frame.add(button)
js> frame.show()
js> function printDate() { print(new Date()) }
js> o = { actionPerformed: printDate }
js> buttonListener = java.awt.event.ActionListener(o)
js> button.addActionListener(buttonListener)

javascript访问java的包和class

java中所有的代码都是class包装了的,而class又是在package下的,rhino为此封装了一个全局对象Packages,通过Packages可以引入所有的java类,如Package.java.lang, Packages.java.io等:

js> Packages.java.io.File
[JavaClass java.io.File]
js> importPackage(java.io)
js> File
[JavaClass java.io.File]

importPackage(java.io)的效果类似java代码中的import java.io.*;
java中的第三方类库也可以通过importClass和importPackage引入,如:
js> importPackage(Packages.org.mozilla.javascript);
js> Context.currentContext
org.mozilla.javascript.Context@1bc887b
js> importClass(java.awt.List)
js> List
[JavaClass java.awt.List]

在引入了java的类库之后,就可以在javascript中使用这些类库了,如:

js> new java.util.Date()
Sun Oct 24 17:46:50 CST 2010
js> new Date()
Sun Oct 24 2010 17:46:54 GMT+0800 (CST)
js> var f = new java.io.File("/etc/hosts");
js> f.exists();
true
js> f.getName();
hosts
js> java.lang.Math.PI
3.141592653589793
js> java.lang.Math.cos(0)
1
js> for (i in f) { print(i) }
getAbsoluteFile
setReadOnly
listFiles
setReadable
writable
hashCode
wait
setExecutable
usableSpace
file
canonicalPath
getUsableSpace
notifyAll
equals
getParent
mkdirs
parent
class
compareTo
freeSpace
getTotalSpace
createNewFile
toString
toURI
toURL
getCanonicalPath
getCanonicalFile
canonicalFile
renameTo
getParentFile
executable
getFreeSpace
absolute
deleteOnExit
canWrite
name
notify
path
canRead
getPath
delete
length
getClass
readable
totalSpace
absoluteFile
lastModified
absolutePath
isAbsolute
list
mkdir
setWritable
isHidden
readOnly
canExecute
isDirectory
hidden
directory
isFile
getName
getAbsolutePath
exists
parentFile
setLastModified
在上面列出的File的方法中,还包括了其从java.lang.Object中继承的所有方法.对于java的重载方法,javascript调用需要用特别的方式.

用javascript实现java的接口

如要实现Runnable接口,按以下方式操作:
js> var obj = { run: function () { print("\nrunning"); } }
js> obj.run()

running
js> var r = new java.lang.Runnable(obj);
js> r.getClass()
class adapter1
js> var t = new java.lang.Thread(r)
Thread[Thread-1,5,main]
js> t.start();
js>
running

用javascript创建java的数组对象

一般直接用javascript创建数组就可以,转为java对象时,rhino会处理类型转换,也可以用以下方法直接创建java数组:
js> var arr = java.lang.reflect.Array.newInstance(java.lang.String, 5); arr[0] = arr[1] = arr[2] = arr[3] = arr[4] = 'create java array using javascript.'
create java array using javascript.
js> arr
[Ljava.lang.String;@1e97f9f
js> arr[1]
create java array using javascript.
js>

Reference: http://www.mozilla.org/rhino/scriptjava.html

Friday, September 17, 2010

maven 学习笔记

maven的POM文件有一份默认的Super POM,所有新建的POM文件都是继承自此POM,这个Super POM的build配置部分如下:


<build>
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<finalName>${artifactId}-${version}</finalName>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>

在WEB项目中会希望在mvn package之后将maven导入的lib文件自动复制到wepapp/WEB-INF/lib下方便测试,如果maven导入的依赖文件发生变化时,将lib目录下的文件先清理之后,再重新加入,同时也可以将其他的lib目录的文件一起复制到webapp/WEB-INF/lib下,要达到这个功能,可以用maven去运行ant的可执行脚本,maven-antrun-plugin 就达到这个目的,只要将ant的任务放到tasks标签里,格式如:

<project>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase> <!-- a lifecycle phase --> </phase>
<configuration>
<tasks>

<!--
Place any Ant task here. You can add anything
you can add between <target> and </target> in a
build.xml.
-->

</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

在linux中,因为默认使用了openjdk,所以在使用maven时,会遇到提示 tools.jar 包的依赖问题,可以在POM中添加下面的配置,引入 tools.jar:

<profiles>
<profile>
<id>default-tools.jar</id>
<activation>
<property>
<name>java.vendor</name>
<value>Sun Microsystems Inc.</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.4.2</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</profile>
</profiles>

在项目目录下运行mvn命令时,如果看到 jvm 1.3 的编译错误,则需要为maven指定源码和JVM的版本,如下:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

在项目下面运行 jUnit test 时,如果运行 mvn test 是成功的,但是单独在一个test文件是运行jUnit test时则报错说 Class not found(或者二者相反),这个是因为maven默认为test的java文件生成的class放到target/test-classes,项目本身的classes output目录可能是设置在webapp/WEB-INF/classes目录中的,二者不一致才造成这个问题,需要在build标签下面设置 outputDirectory 和 testOutputDirectory 这二个标签,让maven也到webapp/WEB-INF/classes目录中查找编译后的文件。

maven中常用命令说明,项目打包和安装到仓库中,在项目下运行:
$> mvn package
为当前项目生成一个jar文件或者是war文件,这个由POM文件配置中的packaging参数决定是jar还是war,运行成功后,会在${basedir}/target目录下生成文件。如果需要将生成的jar文件放到maven仓库中(默认是: ~/.m2/repository),则运行命令:
$> mvn install

为eclipse IDE生成maven项目,配合eclipse maven插件如: m2e - http://m2eclipse.sonatype.org/sites/m2e 一起使用:
$> mvn eclipse:eclipse

运行当前项目中的jUnit test,maven是使用maven-surefire-plugin完成test的,关于这个插件,可以查看 http://tianya23.blog.51cto.com/1081650/386012 中的说明,可以忽略或者指定测试文件的名字,以及在test发生错误如何不影响打包:
$> mvn test

根据上面的maven知识点,配置出符合项目需求的POM配置的build部分如下:

<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>

<outputDirectory>src/main/webapp/WEB-INF/classes</outputDirectory>
<testOutputDirectory>src/main/webapp/WEB-INF/classes</testOutputDirectory>

<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>

<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-lib-src-webapp</id>
<phase>install</phase>
<configuration>
<tasks>
<delete dir="src/main/webapp/WEB-INF/lib" />
<copy todir="src/main/webapp/WEB-INF/lib">
<fileset dir="target/package-name-0.0.1-SNAPSHOT/WEB-INF/lib">
<include name="*" />
</fileset>
</copy>
<copy todir="src/main/webapp/WEB-INF/lib">
<fileset dir="lib">
<include name="*" />
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

</build>

可以从下面的maven仓库中查找包的依赖和maven配置:
* http://repository.apache.org
* http://www.artifact-repository.org
* http://mvnrepository.com
* http://www.mvnbrowser.com
* http://www.jarvana.com
* http://mavensearch.net

Reference:
http://maven.apache.org/general.html
http://maven.apache.org/plugins/
http://maven.apache.org/pom.html
http://maven.apache.org/settings.html
http://maven.apache.org/guides/getting-started/index.html
http://maven.apache.org/plugins/maven-antrun-plugin/usage.html
http://maven.apache.org/plugins/maven-surefire-plugin/usage.html
http://maven.apache.org/guides/introduction/introduction-to-the-pom.html

Monday, March 16, 2009

Test take place of print

[Martin Fowler]: Whenever you are tempted to type something into a print statement or a debugger expression, write it as a test.

Tuesday, March 10, 2009

pentaho2 install in ubuntu

$> export JRE_HOME=/usr/lib/jvm/java-6-sun-1.6.0.10
$> cd pentaho/biserver-ce
$> chmod a+x *.sh
$> ./start-pentaho.sh
$> cd pentaho/biserver-ce/administration-console/
$> ./start.sh
INFO: Console is now started. It can be accessed using http://localhost:8099 or http://127.0.0.1:8099

update admin password to "admin", reference http://wiki.pentaho.com/display/ServerDoc2x/Configuring+Security+with+Pentaho+Administration+Console:
$> cd pentaho/biserver-ce/administration-console/
$> vi resource/config/login.properties
admin: admin,server-administrator,content-administrator,admin

Restart pentaho bi server and pentaho administrator-console server.
Visit http://127.0.0.1:8099, and use admin/admin login administratation console(old username/password is admin/password)

Thursday, March 05, 2009

Howto maven2 download java source jar package

$> mvn dependency:sources -Dsilent=true filename
dependency:sources tells Maven to resolve all dependencies and their source attachments, and displays the version.

maven plugins lists page:
http://maven.apache.org/plugins/maven-dependency-plugin/
http://maven.apache.org/plugins/index.html

Reference:
http://groups.google.com/group/maven-zh/browse_thread/thread/20494aa10d7818ba?pli=1

Friday, February 13, 2009

java 计算字符串长度

/**
* 计算字符串长度,对于0-255之间的字符按1计算,大于255的字符按2计算
*
* @param str
* @return
*/
public static int getStringLength(String str) {
int length = 0;
Pattern pattern = Pattern.compile("([^\\x00-\\xff])");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
length++;
}
return str.length() + length;
}

java unicode字符串转换

/**
* 转换unicode字符串为其对应的实际字符串, UnicodeToString("测试\\u4E2D\\u6587") 输出为: "测试中文"
*
* @param str
* @return
*/
public static String UnicodeToString(String str) {
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
Matcher matcher = pattern.matcher(str);
char ch;
while (matcher.find()) {
ch = (char) Integer.parseInt(matcher.group(2), 16);
str = str.replace(matcher.group(1), ch + "");
}
return str;
}

Reference:
http://yuweijun.blogspot.com/2008/06/unicode.html
http://yuweijun.blogspot.com/2008/08/unicode-and-html-entities-in-javascript.html
http://yuweijun.blogspot.com/2008/12/rubyunicodeutf8.html

Java Pattern.quote 使用说明

Java 引用说明:

\ Nothing,但是引用以下字符
\Q Nothing,但是引用所有字符,直到 \E
\E Nothing,但是结束从 \Q 开始的引用

例子:
Pattern.quote("[test]")
返回 => \Q[test]\E
这样就不需要对正则的特殊字符'['和']'做转义了

Tuesday, February 03, 2009

urlencode and urldecode in java

import java.net.URLDecoder;
import java.net.URLEncoder;

import junit.framework.TestCase;

public class URLEncodeAndDecode extends TestCase {

public void testUrlEncode() throws Exception {
String str = "中文";
String utf8Code = URLEncoder.encode(str, "UTF-8");
assertEquals("%E4%B8%AD%E6%96%87", utf8Code);
String gbkCode = URLEncoder.encode(str, "GBK");
assertEquals("%D6%D0%CE%C4", gbkCode);

assertEquals("中文", URLDecoder.decode("%E4%B8%AD%E6%96%87", "UTF-8"));
assertEquals("中文", URLDecoder.decode("%D6%D0%CE%C4", "GBK"));
}

}

Tuesday, November 18, 2008

Java 多态学习笔记

在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三个基本特征。
将一个方法调用同一个方法主体关联起来称作绑定,程序在运行时能从对象提供的信息中获取对象的类型,从而调用正确的方法体,所以也称为运行时绑定,后期绑定。
多态意味着“不同的形态”,就是对于继承自同一基类的不同子类对象,在相同的接口方法被调用时,会在运行时找到方法相对应的方法体。多态是跟继承协同工作的,是以继承为基础的。
在java中,除了static方法和final方法(private方法也是属于final方法)之后,其他所有的方法都是后期绑定的,通过后期绑定实现多态。这也就是说对于普通的方法调用可以是多态的,而对于静态方法和属性字段则不存在多态。
在继承时,只有public、protected和包可见的方法会被重载,对于基类中的private的方法是不会被子类覆盖的,对于子类而言,是不知道父类中是否有同名的private方法的,子类中同名的private方法就是一个完全不相关的全新方法。

Sunday, November 16, 2008

Send mail through gmail smtp using javamail

import java.security.Security;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.sun.net.ssl.internal.ssl.Provider;

public class GmailSend {
private String mailhost = "smtp.gmail.com";

public synchronized void sendMail(String subject, String body, String sender, String recipients) throws Exception {

Security.addProvider(new Provider());

Properties props = new Properties();
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.host", "smtp.gmail.com");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.quitwait", "false");

Session session = Session.getDefaultInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("test.yu@gmail.com", "****password****");
}
});

MimeMessage message = new MimeMessage(session);
message.setSender(new InternetAddress(sender));
message.setSubject(subject);
message.setContent(body, "text/plain");
if (recipients.indexOf(',') > 0)
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));
else
message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));

Transport.send(message);
System.out.println("finished!");
}

public static void main(String args[]) throws Exception {
GmailSend gmailSend = new GmailSend();
gmailSend.sendMail("send from javamail", "send form javamail by java programmng.", "test.yu@gmail.com",
"test.yu@gmail.com");
}

}

Get mail from gmail using pop of javamail

javamail官方论坛中一个用pop协议从gmail中获取邮件的例子,需要在gmail中开启pop功能。

import java.util.Date;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.internet.ContentType;
import javax.mail.internet.ParseException;

import com.sun.mail.pop3.POP3SSLStore;

public class GmailUtilities {

private Session session = null;
private Store store = null;
private String username, password;
private Folder folder;

public GmailUtilities() {

}

public void setUserPass(String username, String password) {
this.username = username;
this.password = password;
}

public void connect() throws Exception {

String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

Properties pop3Props = new Properties();

pop3Props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
pop3Props.setProperty("mail.pop3.socketFactory.fallback", "false");
pop3Props.setProperty("mail.pop3.port", "995");
pop3Props.setProperty("mail.pop3.socketFactory.port", "995");

URLName url = new URLName("pop3", "pop.gmail.com", 995, "", username, password);

session = Session.getInstance(pop3Props, null);
store = new POP3SSLStore(session, url);
store.connect();

}

public void openFolder(String folderName) throws Exception {

// Open the Folder
folder = store.getDefaultFolder();

folder = folder.getFolder(folderName);

if (folder == null) {
throw new Exception("Invalid folder");
}

// try to open read/write and if that fails try read-only
try {

folder.open(Folder.READ_WRITE);

} catch (MessagingException ex) {

folder.open(Folder.READ_ONLY);

}
}

public void closeFolder() throws Exception {
folder.close(false);
}

public int getMessageCount() throws Exception {
return folder.getMessageCount();
}

public int getNewMessageCount() throws Exception {
return folder.getNewMessageCount();
}

public void disconnect() throws Exception {
store.close();
}

public void printMessage(int messageNo) throws Exception {
System.out.println("Getting message number: " + messageNo);

Message m = null;

try {
m = folder.getMessage(messageNo);
dumpPart(m);
} catch (IndexOutOfBoundsException iex) {
System.out.println("Message number out of range");
}
}

public void printAllMessageEnvelopes() throws Exception {

// Attributes & Flags for all messages ..
Message[] msgs = folder.getMessages();

// Use a suitable FetchProfile
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
folder.fetch(msgs, fp);

for (int i = 0; i < msgs.length; i++) {
System.out.println("--------------------------");
System.out.println("MESSAGE #" + (i + 1) + ":");
dumpEnvelope(msgs[i]);
}

}

public void printAllMessages() throws Exception {

// Attributes & Flags for all messages ..
Message[] msgs = folder.getMessages();

// Use a suitable FetchProfile
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
folder.fetch(msgs, fp);

for (int i = 0; i < msgs.length; i++) {
System.out.println("--------------------------");
System.out.println("MESSAGE #" + (i + 1) + ":");
dumpPart(msgs[i]);
}

}

public static void dumpPart(Part p) throws Exception {
if (p instanceof Message)
dumpEnvelope((Message) p);

String ct = p.getContentType();
try {
pr("CONTENT-TYPE: " + (new ContentType(ct)).toString());
} catch (ParseException pex) {
pr("BAD CONTENT-TYPE: " + ct);
}

/*
* Using isMimeType to determine the content type avoids fetching the
* actual content data until we need it.
*/
if (p.isMimeType("text/plain")) {
pr("This is plain text");
pr("---------------------------");
System.out.println((String) p.getContent());
} else {

// just a separator
pr("---------------------------");

}
}

public static void dumpEnvelope(Message m) throws Exception {
pr(" ");
Address[] a;
// FROM
if ((a = m.getFrom()) != null) {
for (int j = 0; j < a.length; j++)
pr("FROM: " + a[j].toString());
}

// TO
if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
for (int j = 0; j < a.length; j++) {
pr("TO: " + a[j].toString());
}
}

// SUBJECT
pr("SUBJECT: " + m.getSubject());

// DATE
Date d = m.getSentDate();
pr("SendDate: " + (d != null ? d.toString() : "UNKNOWN"));

}

static String indentStr = " ";
static int level = 0;

/**
* Print a, possibly indented, string.
*/
public static void pr(String s) {

System.out.print(indentStr.substring(0, level * 2));
System.out.println(s);
}

}
Usage:

public class GmailPop {

public static void main(String[] args) {

try {

GmailUtilities gmail = new GmailUtilities();
gmail.setUserPass("test.yu@gmail.com", "****password****");
gmail.connect();
gmail.openFolder("INBOX");

int i = 0;
int totalMessages = gmail.getMessageCount();
int newMessages = gmail.getNewMessageCount();

System.out.println("Total messages = " + totalMessages);
System.out.println("New messages = " + newMessages);
System.out.println("-------------------------------");

do {
i++;
gmail.printMessage(i);
} while (i < 10);

// Uncomment the below line to print the body of the message.
// Remember it will eat-up your bandwidth if you have 100's of
// messages.
// gmail.printAllMessageEnvelopes();
// gmail.printAllMessages();

} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}

Tuesday, November 04, 2008

静态成员类与非静态成员类的区别

/**
* 静态成员类与非静态成员类的区别
*/
public class StaticMemberType {

// Interfaces, enumerated types, 和annotation types 无论是否声明static,它们都是static的。
static class StaticInnerClass {
public void test() {
System.out.println("Static Nested Class Method.");

}
}

public void test() {
new NonStaticInnerClass().test();
}

public class NonStaticInnerClass {
// 非静态成员类不可以包含任何static字段、methods或者类型,除非同时使用了static和final的常量字段之外。
// static String CONST1 = "TEST"; // error
final static String CONST2 = "TEST";
public void test() {
System.out.println("Non Static Inner Class.");
}
}

public static void main(String[] args) {
new StaticMemberType.StaticInnerClass().test();

StaticMemberType staticMemberType = new StaticMemberType();
staticMemberType.test();
// new StaticMemberType.NonStaticInnerClass().test(); // error
}
}

Sunday, November 02, 2008

PageLoaderProcessor-Tapestry5核心类

PageLoader会载入一个Tapestry Page,这个过程开销比较大,因此会将完全载入后的Page池化,下一次请求这个Page就将直接从池中获取PagePool.checkout()。

在PageLoader.loadPage()方法中,是调用PageLoaderProcessor中的方法loadPage来获取Page的,这个方法仅会被调用一次,之后这个PageLoaderProcessor对象会被销毁,所以一个页面只有第一次被请求时会触发PageLoaded事件。

PageLoaderProcessor是Tapestry的核心类,通过注入以下services可以实例化得到PageLoaderProcessor对象:ComponentTemplateSource、PageElementFactory、LinkFactory和PersistentFieldManager。

通过ComponentTemplateSource可以获取一个被解析并缓存了的模板文件(tml)对象(ComponentTemplate),PageElementFactory用于创建页面元素(PageElement/ComponentPageElement),LinkFactory负责创建页面上的链接,PersistentFieldManager用于处理页面上被持久化了的属性(Persist Property)。

Wednesday, October 29, 2008

Tapestry5 Page ActionLink 拼装过程

Page.createActionLink ->
LinkFactory.createActionLink ->
InvocationTarget.getPath ->
Link

其中在InvocationTarget的实现类ActionLinkTarget.getPath方法内实际拼装path,path中包括page, component, event等,如test.username:autocomplete。在LinkFactory中调用Link.addParameter方法将page activation context追加到link中。