SAM SUNG CHINH HANG
Tuesday, 13. October 2009, 03:33:47




Hoa có vàng nơi ấy
Tuesday, 13. October 2009, 03:33:47




Monday, 12. October 2009, 08:11:21
![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MÓN HỜI HÔM NAY![]() ![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Monday, 20. April 2009, 15:30:21
I. Khái niệm
1. Stateless Session Bean
- Trạng thái giao dịch liên kết với một client, gọi là trạng thái đặc trưng cho client (client-specific state). Trạng thái này gọi là conversation state, thực tế còn bao gồm cả các kết nối socket, kết nối database, tham chiếu đến bean khác...
- Stateless Session Bean không lưu giữ trạng thái converation Container phân biệt Stateless Session Bean với Stateful Session Bean nhờ những mô tả trong tập tin deployment descriptor ejb-jar.xml.
- Stateless Session Bean được thiết kế để phục vụ cho nhiều client, với những session chỉ có một request.
- Stateless Session Bean chỉ có 2 trạng thái:
•Does Not Exist: không có thực thể bean tồn tại trong bộ nhớ.
•Method-Ready Pool: thực thể bean có mặt trong pool, sẵn sàng phục vụ các triệu gọi business method từ client.
- Stateless Session Bean yêu cầu ít resource nên còn gọi là lightweight bean.
2. Vòng đời của Stateless Session Bean
- EJB Container quản lý các thực thể bean. Khi cần thực thể, thực thể bean được khởi tạo bằng cách dùng phương thức Class.newInstance() trên lớp bean. Sau đó phương thức setSessionContext( sc ) của thực thể bean được triệu gọi để thực thể bean nhận tham chiếu đến đối tượng SessionContext. Thực thể bean cần SessionContext để truy xuất thông tin môi trường: identity và role của client, transaction context,… Cuối cùng phương thức ejbCreate() không đối số của bean được EJB Container triệu gọi (chỉ một lần trong vòng đời của bean). Lúc này bean đã ở trạng thái sẵn sàng thực hiện các yêu cầu của client do EJB(Local) Object ủy nhiệm (delegate) đến, gọi là trạng thái Method-Ready Pool.
- Do không cần lưu trữ trạng thái giao dịch, Stateless Session Bean không quan tâm đến việc kích hoạt (activation) bean, container không bao giờ gọi đến các phương thức callback ejbActivate() và ejbPassivate() của nó. Ra khỏi trạng thái Method-Ready Pool, bean sẽ rơi vào trạng thái Does Not Exits nghĩa là container không cần nó nữa. Khả năng lưu trữ của pool là cơ sở để container thu giảm số bean ở trạng thái Method-Ready Pool bằng phương thức ejbRemove(), giải phóng tài nguyên và hủy bean. Xem phần Instance swapping phía dưới để hiểu rõ cơ chế.
3. Các phương thức callback
- Phương thức void ejbCreate() chỉ có duy nhất một và không tham số vì không cần khởi tạo trạng thái conversation. Session bean phải có ít nhất một phương thức ejbCreate(). Thường rỗng do client không triệu gọi đến.
- Phương thức void ejbRemove() thường rỗng do client không triệu gọi đến.
- Phương thức void ejbPassivate() rỗng vì container không bao giờ thụ động hóa thực thể bean.
- Phương thức void ejbActivate() rỗng vì container không bao giờ kích hoạt thực thể bean.
- Phương thức void setSessionContext( SessionContext ctx ) thường rỗng vì bean không có biến thực thể (biến lớp riêng) nên không cần lưu các tham chiếu đến các biến đó.
4. Hoạt động của Stateless Session Bean
1- Container đăng ký tất cả bean đã triển khai với JNDI với tên JNDI chỉ định trong deployment descriptor.
2- Container chịu trách nhiệm quyết định tạo thực thể bean tùy theo chính sách lưu (caching). Container lần lượt gọi các phương thức Class.newInstance(), setSessionContext()và ejbCreate().
3- Client tìm thấy Home(Local) interface của bean bằng cách lookup()thông qua JNDI.
4- Client dùng phương thức create() của Home(Local) interface để tạo ra EJB(Local) Object của bean. Chú ý phương thức này không triệu gọi ejbCreate() trên bean.
5- Client gọi các business method thông qua EJB(Local) Object, lời gọi này sẽ được container ủy nhiệm đến bean.
6- Container chịu trách nhiệm quyết định loại bỏ thực thể bean bằng cách gọi ejbRemove(). Không loại bỏ thực thể bean bằng cách gọi phương thức remove() của Home(Local) interface, phương thức này không làm gì cả.
5. Quản lý thực thể với Stateless Session Bean
a) Instance Pool
- Các thực thể bean sẽ được tạo khi container hoạt động. Instance pooling là cơ chế để thu giảm số thực thể bean cần có mặt cho việc phục vụ các yêu cầu của client, giảm chi phí tài nguyên khi tạo và hủy bean bằng cách dùng lại các thực thể có trong pool. Như vậy thu giảm việc sử dụng tài nguyên.
- Các instance pool đều cố gắng quản lý các tập hợp bean sao cho có thể truy xuất nhanh các bean trong thời gian chạy. Để thiết lập instance pool, container tạo một số thực thể của lớp bean và giữ chúng cho đến khi cần đến. Khi client yêu cầu một business method, thực thể bean từ pool được gán đến EJB(Local) Object liên kết với client. Khi một EJB(Local) Object không cần đến thực thể, bean được trả về cho instance pool.
- Một EJB server duy trì nhiều instance pool cho mỗi kiểu pool được triển khai. Mọi thực thể trong instance pool là tương đương với nhau. Thực thể bean sẽ được chọn tùy ý để gán đến EJB(Local) Object cần đến nó. Số thực thể trong bean dao động do hoạt động vào/ra của bean.
- Sau khi thực thể bean được đặt trong pool, gọi là trạng thái Pooled, nó lấy tham chiếu đến một javax.ejb.EJBContext. EJBContext cung cấp một giao diện để bean có thể dùng liên lạc với môi trường EJB.
- Khi bean liên kết với một EJB(Local) Object, nó ở trạng thái Ready. Lúc này EJBContext có một ý nghĩa mới, nó cung cấp thông tin về client dùng bean, cần khi bean truyền tham chiếu đến chính bean hoặc các bean khác.
b) Instance swapping (hoán chuyển thực thể bean)
- Sau khi phục vụ yêu cầu của client, bean tách rời EJB Object và quay trở về instance pool. Nếu client yêu cầu đến EJB Object mà không có thực thể bean liên kết với nó, container sẽ tìm bean trong pool và lại gán cho EJB Object. Thao tác này gọi là instance swapping.
- Stateless Session Bean không cần lưu trữ trạng thái conversation trong nó nên mọi triệu gọi phương thức từ nó tiến hành độc lập. Điều này có nghĩa bất kỳ Stateless Session Bean nào cũng có thể phục vụ yêu cầu cho bất kỳ EJB Object nào có kiểu ủy nhiệm hợp lệ đến nó. Container có thể hoán chuyển các thực thể bean vào hoặc ra giữa các triệu gọi phương thức.
- Hình trên mô tả cơ chế hoán chuyển thực thể khi triệu gọi phương thức của Stateless Session Bean: Bean A phục vụ một triệu gọi business method được ủy nhiệm từ EJB Object 1 (a). Khi bean A thực hiện xong yêu cầu nó chuyển ngược trở về instance pool (b). Khi client triệu gọi phương thức trên EJB Object 2, bean A lại liên kết với EJB Object 2 để phục vụ yêu cầu này (c). Khi bean A đang phục vụ, nếu có một triệu gọi trên EJB Object 1, bean B sẽ phục vụ yêu cầu này.
- Dùng chiến lược hoán chuyển trên, vài bean có thể phục vụ cho hàng trăm client. Khi một thực thể bean chấm dứt phục vụ, nó lập tức trở về trạng thái sẵn sàng trong instance pool cho một EJB Object bất kỳ cần ủy nhiệm đến nó.
6. Lớp và giao diện
- Hàm dựng (constructor) nói chung không dùng khi tạo lớp bean, nếu có phải là hàm dựng mặc định (không đối số) và public. Trong lớp bean không có các phương thức finalize.
+ void ejbActivate()
a) Client truy xuất từ xa (remote client view)
II. Thiết kế và triển khai
A. Tạo Stateless Session Bean
- Cần có gói javax.ejb trong CLASSPATH: nghĩa là cần có ejb-2_1-api.jar, hoặc j2ee.jar (nếu có cài đặt j2eesdk), hoặc jboss-j2ee.jar (%JBOSS_HOME%\client) trong CLASSPATH. Cần chú ý đến phiên bản của EJB đang triển khai.
1. Lớp EJB
- Lớp EJB cài đặt:
•Các phương thức quan trọng nhất của EJB là các business method (phương thức nghiệp vụ). EJB được thiết kế nhằm mục tiêu giúp người lập trình chỉ quan tâm đến việc thực hiện các business method. Các business method này cùng tên với phương thức khai báo trong EJB interface để có thể delegate từ đó được, nhưng không cần ném RemoteException vì được delegate, mà không triệu gọi từ xa. Các phương thức này không được bắt đầu bằng ejb, không được static hoặc final và phải public.
•Các phương thức bắt buộc cài đặt, dành cho container dùng quản lý EJB, gọi là các phương thức callback. Các phương thức này thừa kế từ giao diện javax.ejb.SessionBean.
Lớp EJB không chứa các tác vụ cấp hệ thống (persistence, security, transaction, …) nên dễ triển khai hơn RMI nhiều.
- Lớp EJB cần phải:
•import các giao diện: javax.ejb.SessionBean, javax.ejb.SessionContext.
•thừa kế giao diện javax.ejb.SessionBean.
•Nếu có constructor phải là constructor mặc định (không đối số) và không có phương thức finalize.
package myejb.session;
import javax.ejb.*;
import javax.naming.*;
public class ConvertBean implements SessionBean {
private SessionContext ctx;
private Context environment;
// Callback methods
public void setSessionContext( SessionContext sc ) {
this.ctx = sc;
}
public void ejbCreate() throws CreateException {
try {
InitialContext ic = new InitialContext();
environment = ( Context )ic.lookup( "java:comp/env" );
} catch ( NamingException ne ) {
throw new CreateException( "Could not look up context" );
}
}
public void ejbRemove() { }
public void ejbActivate() {}
public void ejbPassivate() { }
// Business methods
public double dollarToVND( double dollars ) {
Double rate = new Double( 0 );
try {
rate = ( Double )environment.lookup( "ExchangeRate" );
} catch ( NamingException ne ) {
System.out.println( "Invalid Exchange Rate" );
}
return dollars * rate.doubleValue();
}
}
- Passivation và Activation chỉ thực hiện trên Stateful Session Bean, không thực hiện trên Stateless Session Bean nhưng có trong giao diện javax.ejb.SessionBean.
Business logic của bean trên là phương thức dollarToVND() chuyển đổi tiền từ USD sang VND. Tỷ giá hối đoái (exchange rate) được lưu và tham chiếu như một thuộc tính ENC trong tập tin DD ejb-jar.xml.
2. Các giao diện
- Tùy kịch bản sử dụng, một trong hai hoặc cả hai loại giao diện sau sẽ được triển khai. Có thể dùng XDoclet để sinh các giao diện này một cách tự động.
a) Giao diện truy xuất từ xa (outside view, remote view)
- Cặp giao diện truy xuất từ xa dùng khi có triệu gọi các business method của EJB từ xa, ví dụ từ ứng dụng client độc lập, từ Web tier thuộc Application server khác. Gồm: Remote interface và Remote Home interface.
- Remote interface khai báo tất cả các business method của EJB mà client sẽ triệu gọi từ xa, vì vậy có ném RemoteException khi lời triệu gọi thất bại. Các business method khai báo ở đây sẽ được cài đặt trong lớp EJB và sẽ được Remote interface ủy nhiệm đến.
Remote interface là một giao diện “bộc lộ” các business method của EJB liên kết với nó cho phía client triệu gọi.
Remote interface cần phải:
•import các giao diện javax.ejb.EJBObject và java.rmi.RemoteException.
•Remote interface phải public (để có thể triệu gọi từ xa) và thừa kế giao diện javax.ejb.EJBObject.
•Các business method được định nghĩa ở đây có khả năng ném ra java.rmi.RemoteException khi gặp sự cố (mạng, server, …)
package myejb.session;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface Convert extends EJBObject {
public double dollarToVND( double dollars ) throws RemoteException;
}
- Home interface định nghĩa các phương thức quản lý vòng đời của bean, hoạt động như một factory . Home interface được tạo ra cùng cặp với giao diện triệu gọi tương ứng. Với Remote interface, ta có Remote Home interface.
Giao diện này cần phải:
•import các giao diện: java.rmi.RemoteException, javax.ejb.CreateException và javax.ejb.EJBHome.
•Remote Home interface phải thừa kế giao diện javax.ejb.EJBHome.
•Có phương thức create() ném ra các exception: RemoteException và CreateException (cùng với các exception của người dùng nếu có) và trả về một EJB Remote Object có kiểu Remote interface.
package myejb.session;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface ConvertHome extends EJBHome {
Convert create() throws java.rmi.RemoteException,CreateException;
}
Phương thức create() của Stateless Session Bean không nhận bất kỳ một đối số nào vì không cần lưu trữ trạng thái conversation giữa client và server.
b) Giao diện truy xuất cục bộ (inside view, local view)
- Giao diện truy xuất cục bộ tương tự giao diện truy xuất từ xa nhưng dùng khi triệu gọi EJB cục bộ từ một EJB khác hoặc từ JSP, servlet thuộc Web tier trong cùng ứng dụng J2EE. Giao diện truy xuất cục bộ không dựa trên RMI và thường được dùng trong một JVM. Gồm: Local interface và Local Home interface.
- Local interface cần phải:
•import giao diện javax.ejb.EJBLocalObject.
•Local interface phải public và thừa kế giao diện javax.ejb.EJBLocalObject.
•Các business method được định nghĩa ở đây không ném ra java.rmi.RemoteException khi gặp sự cố, vì được triệu gọi cục bộ.
package myejb.session;
import javax.ejb.EJBLocalObject;
public interface ConvertLocal extends EJBLocalObject {
public double dollarToVND( double dollars );
}
- Local Home interface tương tự Remote Home interface, nhưng dùng chung cặp với Local interface, phương thức create() của nó được gọi cục bộ nên không ném ra RemoteException.
Local Home interface cần phải:
•import các giao diện: javax.ejb.CreateException và javax.ejb.EJBLocalHome.
•Local Home interface phải thừa kế giao diện javax.ejb.EJBLocalHome.
•Có phương thức create() ném ra exception CreateException cùng với các exception của người dùng nếu có và trả về một EJB Local Object có kiểu Local interface.
package myejb.session;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
public interface ConvertLocalHome extends EJBLocalHome {
ConvertLocal create() throws CreateException;
}
3. Deployment Descriptor (DD)
- Chuẩn đóng gói các component của J2EE quy định EJB được đóng vào gói .JAR, kèm theo tập tin mô tả triển khai (Deployment Descriptor) ejb-jar.xml. Ta dùng Ant để thực hiện việc đóng gói.
- JBoss cung cấp một XML Editor là ejx.jar (chỉ dùng cho EJB1.1) nhưng từ sau phiên bản 2.1 không thấy gói này nữa. Có thể dùng tiện ích soạn thảo bất kỳ để tạo tập tin XML trên. Nếu dùng XDoclet, các tập tin mô tả cũng được sinh ra tự động như các giao diện.
- Trong DD, người phát triển bean cần cung cấp các thông tin mà EJB container không thể nhận được bằng cách “nội soi” (introspection) các lớp.
<?xml version="1.0"?>
<ejb-jar version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">
<enterprise-beans>
<session>
<ejb-name>Convert</ejb-name>
<home>myejb.session.ConvertHome</home>
<remote>myejb.session.Convert</remote>
<local-home>myejb.session.ConvertLocalHome</local-home>
<local>myejb.session.ConvertLocal</local>
<ejb-class>myejb.session.ConvertBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<env-entry>
<env-entry-name>ExchangeRate</env-entry-name>
<env-entry-type>java.lang.Double</env-entry-type>
<env-entry-value>15740.0</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Convert</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Supports</trans-attribute>
</container-transaction>
<security-role>
<description>Users</description>
<role-name>users</role-name>
</security-role>
</assembly-descriptor>
</ejb-jar>
Với ví dụ trên, chỉ cần element <enterprise-beans>. Các element khác chỉ minh họa thêm phần transaction và security, sẽ thảo luận sau.
- Mỗi component của ứng dụng J2EE có một JNDI ENC riêng (Enterprise Naming Context), cung cấp nơi đăng ký các đối tượng phân tán, thường dùng khi truy xuất cục bộ. Trong đó, java:comp là đặc tả component (component – specific) riêng của JNDI ENC. Một số thông tin được khai báo trong các DD chuẩn và được truy xuất thông qua JNDI:
•Các mục nhập (thuộc tính) môi trường (environment entry), khai báo trong các element <env-entry>. Xem ví dụ khai báo thuộc tính ENC ExchangeRate trong DD ejb-jar.xml trên.
•Các tham chiếu đến EJB, khai báo trong các element <ejb-ref> và <ejb-local-ref>.
•Các tham chiếu đến nguồn kết nối dữ liệu (resource manager connection factory), khai báo trong các element <resource-ref>.
•Các tham chiếu tài nguyên môi trường (resource environment), khai báo trong các element <resource-env-ref>.
B. Tạo client truy xuất Stateless Session Bean
1. Client là ứng dụng độc lập
- Sau khi triển khai, Home Object của EJB được đăng ký trong cây JNDI. Để truy xuất bean ta lần lượt thực hiện:
a) Định vị Home Object
- Client dùng tên đăng ký JNDI để định vị Home Object.
•Thiết lập thuộc tính môi trường (Initial Context Factory, vị trí server cung cấp dịch vụ Naming, …) cho JVM của client. Các cách thiết lập đã được giới thiệu trong chương 1. Trong ví dụ minh họa này, ta tạo tập tin jndi.properties có nội dung:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=venus:1099
venus là hostname (cũng có thể dùng địa chỉ IP, địa chỉ vu hồi localhost – 127.0.0.1, …) của máy chủ chạy JBoss. Port 1099 là mặc định cho JNDI.
•Tạo JNDI naming context như một giao diện giữa client và JNDI.
Context ctx = new InitialContext();
b) Tìm (lookup) đối tượng thông qua JNDI
- Sau khi tạo JNDI context, phương thức lookup() của đối tượng lớp javax.naming.InitialContext được sử dụng để định vị đối tượng có tên JNDI chỉ định. Phương thức này trả về một đối tượng (kiểu Object chung).
Object obj = ctx.lookup( "Convert" );
c) Thu hẹp (narrow) tham chiếu
- Đối tượng trả về bởi phương thức lookup()trong trường hợp client truy xuất từ xa có thể là đối tượng CORBA hoặc Java. Để tổng quát hơn, nên thu hẹp tham chiếu cho phép ép kiểu một cách tường minh đối tượng nhận được thành kiểu home interface. Điều này được thực hiện bởi phương thức PortableRemoteObject.narrow(), có hai tham số: đối tượng do lookup() trả về và tên tập tin class của home interface. Lớp javax.rmi.PortableRemoteObject được dùng thay cho lớp java.rmi.server.UnicastRemoteObject trong RMI để bảo đảm tính tương thích với các giao thức khác JRMP, ví dụ RMI/IIOP.
ConvertHome home = ( ConvertHome )PortableRemoteObject.narrow( obj, ConvertHome.class );
- Trong trường hợp client truy xuất cục bộ, không cần đến phương thức này.
d) Sinh ra một thực thể EJB
- EJB sẽ triệu gọi phương thức create() của đối tượng remote home để trả về EJB Object (đối tượng remote interface).
Convert convert = home.create();
e) Triệu gọi các business method
- EJB Interface định nghĩa các business method thực hiện trong lớp EJB, client sẽ triệu gọi các phương thức này thông qua tham chiếu đến EJB Object do phương thức create() trả về. Khi EJB Object nhận lời triệu gọi, nó ủy nhiệm (delegate) cho bean bên trong liên quan thực hiện.
vnd = convert.dollarToVND( amt );
f) Client truy xuất từ xa
- Chương trình client sau có giao diện Swing, các thao tác chủ yếu được thực hiện trong phương thức actionperformed() của lớp ButtonListener. Chú ý tên JNDI của bean khi truy xuất từ xa.
package clients;
import myejb.session.Convert;
import myejb.session.ConvertHome;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
public class ConvertClient extends JFrame {
public static String value;
public static double vnd;
public static double amt;
Container c;
JTextField t = new JTextField( 10 );
JButton b = new JButton( "Convert" );
JLabel result = new JLabel();
public ConvertClient( String s ) {
super( s );
c = getContentPane();
c.setLayout( new GridLayout( 2, 2, 2, 2 ) );
c.add( new JLabel( "Enter the amount in USD:" ) );
c.add( t );
c.add( b );
c.add( result );
value = t.getText();
b.addActionListener( new ButtonListener() );
setSize( 400, 95 );
setVisible( true );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
class ButtonListener implements ActionListener {
public void actionPerformed( ActionEvent ev ) {
value = t.getText();
amt = Double.parseDouble( value );
try {
Context ctx = new InitialContext();
Object obj = ctx.lookup( "Convert" );
ConvertHome home = (ConvertHome)PortableRemoteObject.narrow(obj,ConvertHome.class);
Convert convert = home.create();
vnd = convert.dollarToVND( amt );
convert.remove();
if ( vnd >= 1E6 )
result.setText( String.valueOf( vnd/1000000 ) + " million(s) VND" );
else
result.setText( String.valueOf( vnd ) + " VND" );
ctx.close();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
public static void main( String[] args ) {
new ConvertClient( "Convert Tool" );
}
}
2. Client là Web tier (truy xuất cục bộ)
- Servlet ConvertSevlet.java là client truy xuất EJB cục bộ, gồm hai phần:
•doGet(): dùng để hiển thị form ban đầu vì lúc đầu gọi trang bằng GET; hoặc dùng để hiển thị form phía trên kết quả, do doPost() gọi doGet() trước tiên.
•doPost(): dùng để hiển thị kết quả vì lúc này gọi trang bằng POST thông qua form. Kết quả có được từ việc triệu gọi cục bộ EJB.
- Khi triệu gọi EJB thông qua giao diện truy xuất cục bộ, không cần thiết lập các thuộc tính môi trường liên quan JNDI vì client đã lấy thông tin môi trường từ Container, ta chỉ sử dụng một thực thể InitialContext mặc định để lookup Local Home Object từ ENC hoặc tên JNDI. Cũng không cần thu hẹp tham chiếu nhận được bằng phương thức narrow() của lớp PortableRemoteObject.
import myejb.session.*;
import javax.naming.*;
import java.io.PrintWriter;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.ejb.CreateException;
public class ConvertServlet extends javax.servlet.http.HttpServlet {
private ConvertLocalHome home = null;
public void init( ServletConfig conf ) throws ServletException {
super.init( conf );
try {
Context ctx = new InitialContext();
if ( home == null )
home = ( ConvertLocalHome )ctx.lookup( "java:comp/env/Convert" );
} catch ( NamingException e ) {
e.printStackTrace ();
}
}
public void doGet( HttpServletRequest req, HttpServletResponse res )
throws ServletException ,IOException {
res.setContentType( "text/html" );
PrintWriter out = ( PrintWriter )res.getWriter();
out.println( "<html><head>Convert " );
out.println( "<style>input.std { width:200; }" );
out.println( "div.frame { font-family:verdana; font-size: 9pt;}" );
out.println( "</style></head><body>");
out.println( "<form action=\"ConvertServlet\" method=\"post\">" );
out.print( "Enter the amount in USD: " );
out.println( "<input type=\"text\" name=\"amt\" class=\"std\" />
" );
out.println( "<input type=\"submit\" value=\"Convert\" /></form>" );
out.println( "</body></html>" );
}
public void doPost( HttpServletRequest req, HttpServletResponse res )
throws ServletException, IOException {
double vnd = 0.0;
doGet(req,res);
PrintWriter out = ( PrintWriter )res.getWriter();
try {
ConvertLocal convert = home.create();
vnd = convert.dollarToVND( Double.parseDouble( req.getParameter( "amt" ) ) );
convert.remove();
} catch ( Exception ex ) {
out.println( "
Error: " + ex.toString() );
}
String result = "";
if ( vnd >= 1E6 )
result = String.valueOf( vnd/1000000 ) + " million(s) VND";
else
result = String.valueOf( vnd ) + " VND";
out.println( "<html><head><style>" );
out.println( "p { font-family:verdana;font-size:9pt; }</style></head>" );
out.println( "<body>Convert result:
" );
out.println( req.getParameter( "amt" ) + "USD = " + result + ".
" );
out.println( "</body></html>" );
}
}
- Module Web cần DD web.xml cho gói .WAR của ứng dụng Web. Nếu dùng XDoclet, DD này cũng được sinh ra một cách tự động.
<?xml version="1.0"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<display-name>Convert</display-name>
<welcome-file-list>
<welcome-file>ConvertServlet</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>ConvertServlet</servlet-name>
<servlet-class>ConvertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ConvertServlet</servlet-name>
<url-pattern>/ConvertServlet</url-pattern>
</servlet-mapping>
<ejb-local-ref>
<ejb-ref-name>Convert</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home>myejb.session.ConvertLocalHome</local-home>
<local>myejb.session.ConvertLocal</local>
<ejb-link>convert.jar#Convert</ejb-link>
</ejb-local-ref>
</web-app>
- Tham chiếu cục bộ đến EJB được khai báo bằng cách dùng element <ejb-local-ref> trong DD web.xml trên. Element này chứa các element lồng:
•Element tùy chọn <description> chứa mô tả.
•Element <ejb-ref-name> chứa tên của tham chiếu liên quan đến context java:comp/env.
•Element <ejb-ref-type> chỉ định kiểu của EJB. Phải là Entity hoặc Session.
•Cặp element <local> và <local-home> chứa tên đầy đủ cặp giao diện truy xuất cục bộ của EJB cần tham chiếu.
•Element tùy chọn <ejb-link> kết nối tham chiếu đến một EJB khác trong cùng gói EJB hoặc trong cùng ứng dụng J2EE. Trị của <ejb-link> là <ejb-name> của bean được tham chiếu. Nếu có nhiều EJB cùng <ejb-name> trị này sẽ là đường dẫn đến gói EJB (.jar), <ejb-name> của bean cần tham chiếu gắn phía sau tên gói EJB, tách ra bởi dấu #. Như vậy trong DD trên trị của <ejb-link> là Convert hoặc cụ thể hơn convert.jar#Convert đều được. Element <ejb-link> phải được chỉ định trong JBoss để so trùng tham chiếu cục bộ đến bean tương ứng.
- Ứng dụng J2EE cũng cần DD application.xml cho việc lắp ráp ứng dụng J2EE, tạo thành gói .EAR.
<?xml version="1.0"?>
<application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com /xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/application_1_4.xsd">
<display-name>Convert</display-name>
<module>
<web>
<web-uri>convert.war</web-uri>
<context-root>Convert</context-root>
</web>
</module>
<module>
<ejb>convert.jar</ejb>
</module>
</application>
2. Tạo build.xml để triển khai nhanh bằng Ant
- Chuẩn bị tập tin build.xml có nội dung như sau:
<?xml version="1.0"?>
<project name="JBoss" default="assemble" basedir=".">
<property environment="env" />
<property name="src.dir" value="${basedir}/src" />
<property name="websrc.dir" value="${basedir}/servlet" />
<property name="src.resources" value="${basedir}/src/resources" />
<property name="jboss.home" value="${env.JBOSS_HOME}" />
<property name="build.dir" value="${basedir}/build" />
<property name="build.classes.dir" value="${build.dir}/classes" />
<property name="app.name" value="convert" />
<path id="classpath">
<fileset dir="${jboss.home}/client">
<include name="**/*.jar" />
</fileset>
<pathelement location="${basedir}/lib/j2ee.jar" />
<pathelement location="${build.classes.dir}" />
<pathelement location="${basedir}/jndi" />
</path>
<target name="prepare">
<delete dir="${build.dir}" />
<mkdir dir="${build.dir}" />
<mkdir dir="${build.dir}/servlet" />
<mkdir dir="${build.classes.dir}" />
</target>
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}"
destdir="${build.classes.dir}"
debug="on"
deprecation="on"
optimize="off"
includes="**">
<classpath refid="classpath" />
</javac>
</target>
<target name="ejbjar" depends="compile">
<jar jarfile="${build.dir}/${app.name}.jar">
<fileset dir="${build.classes.dir}">
<include name="myejb/session/*.class" />
</fileset>
<fileset dir="${src.resources}/beans">
<include name="**/*.xml" />
</fileset>
</jar>
</target>
<target name="webwar">
<javac srcdir="${websrc.dir}"
destdir="${build.dir}/servlet"
debug="on"
deprecation="on"
optimize="off"
includes="**">
<classpath refid="classpath" />
</javac>
<war warfile="${build.dir}/${app.name}.war" webxml="${src.resources}/web/web.xml">
<fileset dir="${build.dir}/servlet" />
</war>
</target>
<target name="assemble" depends="ejbjar,webwar">
<ear earfile="${build.dir}/${app.name}.ear"
appxml="${src.resources}/app/application.xml">
<fileset dir="${build.dir}" includes="*.jar,*.war" />
</ear>
<delete file="${build.dir}/${app.name}.jar" />
<delete file="${build.dir}/${app.name}.war" />
<move file="${build.dir}/${app.name}.ear"
todir="${jboss.home}/server/default/deploy" />
</target>
<target name="run.client">
<java classname="clients.ConvertClient" fork="yes" dir=".">
<classpath refid="classpath" />
</java>
</target>
<target name="clean">
<delete dir="${build.dir}" />
<delete file="${jboss.home}/server/default/deploy/${app.name}.ear" />
</target>
</project>
3. Triển khai và chạy ứng dụng
a) Chạy JBoss server
- Chạy %JBOSS_HOME%\bin\run.bat trong một console.
b) Chạy Ant
- Dùng Ant để tự động biên dịch, đóng gói, lắp ráp ứng dụng và triển khai nhanh: ant
- Ngay sau khi gói ứng dụng J2EE convert.ear được tạo trong thư mục build và được sao chép một cách tự động vào thư mục %JBOSS_HOME%\server\default\deploy\, lập tức thấy chi tiết triển khai gói này trong console chạy JBoss server. Đây là khả năng hot deployment của JBoss.
- Cũng có thể theo dõi kết quả triển khai trong jmx-console quản lý JBoss:
Monday, 20. April 2009, 15:20:15
1. Local và Remote interface
2. Quản lý tài nguyên
a) Instance Pool
- Các thực thể bean sẽ được tạo khi container hoạt động. Instance pooling là cơ chế để thu giảm số thực thể bean cần có mặt cho việc phục vụ các yêu cầu của client, giảm chi phí tài nguyên khi tạo và hủy bean bằng cách dùng lại các thực thể có trong pool. Như vậy thu giảm việc xử dụng tài nguyên.
- Các instance pool đều cố gắng quản lý các tập hợp bean sao cho có thể truy xuất nhanh các bean trong thời gian chạy. Để thiết lập instance pool, container tạo một số thực thể của lớp bean và giữ chúng cho đến khi cần đến. Khi client yêu cầu một business method, thực thể bean từ pool được gán đến EJB Object liên kết với client. Khi một EJB Object không cần đến thực thể, bean được trả về cho instance pool.
- Một EJB server duy trì nhiều instance pool cho mỗi kiểu pool được triển khai. Mọi thực thể trong instance pool là tương đương với nhau. Thực thể bean sẽ được chọn tùy ý để gán đến EJB Object cần đến nó. Số thực thể trong bean dao động do hoạt động vào/ra của bean.
- Sau khi thực thể bean được đặt trong pool, gọi là trạng thái Pooled, nó lấy tham chiếu đến một javax.ejb.EJBContext. EJBContext cung cấp một giao diện để bean có thể dùng liên lạc với môi trường EJB.
- Khi bean liên kết với một EJB Object, nó ở trạng thái Ready. Lúc này EJBContext có một ý nghĩa mới, nó cung cấp thông tin về client dùng bean, cần khi bean
truyền tham chiếu đến chính bean hoặc các bean khác.
b) Instance swapping (hoán chuyển thực thể bean)
- Sau khi phục vụ yêu cầu của client, bean tách rời EJB Object và quay trở về instance pool. Nếu client yêu cầu đến EJB Object mà không có thực thể bean liên kết với nó, container sẽ tìm bean trong pool và lại gán cho EJB Object. Thao tác này gọi là instance swapping.
- Stateless Session Bean không cần lưu trữ trạng thái conversation trong nó nên mọi triệu gọi phương thức từ nó tiến hành độc lập. Điều này có nghĩa bất kỳ Stateless Session Bean nào cũng có thể phục vụ yêu cầu cho bất kỳ EJB Object nào có kiểu hợp lệ ủy nhiệm đến nó. Container có thể hoán chuyển các thực thể bean vào hoặc ra giữa các triệu gọi phương thức.
- Hình dưới mô tả cơ chế hoán chuyển thực thể khi triệu gọi phương thức của Stateless Session Bean: Bean A phục vụ một triệu gọi business method được ủy nhiệm từ EJB Object 1 (a). Khi bean A thực hiện xong yêu cầu nó chuyển ngược trở về instance pool (b). Khi client triệu gọi phương thức trên EJB Object 2, bean A lại liên kết với EJB Object 2 để phục vụ yêu cầu này (c). Khi bean A đang phục vụ, nếu có một triệu gọi trên EJB Object 1, bean B sẽ phục vụ yêu cầu này.
- Dùng chiến lược hoán chuyển này, vài bean có thể phục vụ cho hàng trăm client. Khi một thực thể bean chấm dứt phục vụ, nó lập tức trở về trạng thái sẵn sàng trong instance pool cho một EJB Object bất kỳ cần ủy nhiệm đến nó.
c) Cơ chế activation và passivation
- Không giống như Stateless Session Bean, Entity Bean và Message-Driven Bean, Stateful Session Bean không tham gia vào instance pool. Thay vào đó nó dùng cơ chế passivation và activation để tiết kiệm tài nguyên. Khi container cần tiết kiệm tài nguyên, nó có thể loại bean ra khỏi bộ nhớ, lúc này trạng thái của bean sẽ được lưu trữ (serialize) xuống thiết bị lưu trữ. Khi client triệu gọi phương thức của bean, một thực thể bean mới lại được tạo ra, chứa trạng thái conversation do bean trước lưu trữ.
- Passivation (thụ động hóa) tách bean ra khỏi EJB Object liên kết với nó và lưu trạng thái chứa trong bean (trạng thái kết liên hệ với EJB Object và trạng thái conversation), sau đó loại bean ra khỏi bộ nhớ. Client không biết điều này và có thể vẫn liên lạc với EJB Object trong khi bean đã thụ động hóa.
- Activation (kích hoạt) hồi phục lại thực thể bean liên kết với EJB Object. Lúc này container sẽ tự động tạo một thực thể mới và thiết lập các field theo dữ liệu được lưu trữ khi passivation. Sau đó EJB Object có thể ủy nhiệm các triệu gọi phương thức từ client đến bean như bình thường.
- Hình bên trình bày quá trình passivation và activation một Sateful Session Bean. (a) bean B được thụ động hóa, trạng thái của bean B được lưu trữ; (b) bean B tách ra khỏi EJB Object, loại khỏi bộ nhớ; (c) bean được kích hoạt, một thực thể mới, bean C được tạo ra với thông tin lưu trữ từ bean B và liên kết với EJB Object từ các thông tin nhận được.
3. Session Bean
- Một Session Bean thực hiện một conversation giữa client và server. Session Bean thực hiện một tác vụ bussiness theo yêu cầu của client trong một session đơn. Chúng thực hiện các bussiness logic (logic nghiệp vụ) như: workflow (chuỗi công việc), algorithm (thuật toán cho một công việc), bussiness rule (kiểm tra các luật bussiness).
- Một Session Bean giống như một phần mở rộng của client trên server, như bussiness của client được tách ra và chuyển đến server. Thực tế Session Bean cũng có thể nằm phía client (client tier) như một application client J2EE.
- Ví dụ một Session Bean có thể gửi email, giúp quản lý workflow, thực hiện các thuật toán như nén, mã hóa, ...
- Session Bean có các tính chất sau:
•Thể hiện một conversation giữa client và server.
•Thực hiện đại diện cho một client đơn. Không thể chia sẻ cho nhiều client cùng lúc. Như vậy không thể gọi bởi cùng client bằng cách dùng multithread.
•Có thể thực hiện transaction và security.
•Không thể hiện dữ liệu trực tiếp trong cơ sở dữ liệu. Tuy nhiên chúng có thể truy xuất và cập nhập dữ liệu giống như client thường làm.
•Có đời sống ngắn. Nó bị loại bỏ khi client loại bỏ nó lúc chấm dứt session, hoặc khi container ngưng vì một lý do nào đó.
- Có hai kiểu session bean:
•Stateless Session Bean: (bean không lưu vết) không lưu giữ trạng thái của conversation liên kết với một client, gọi là client-specific state (trạng thái đặc trưng cho client. Client phải chiu trách nhiệm duy trì trạng thái conversation nếu cần. Container sẽ dùng lại cùng một thực thể bean để phục vụ cho nhiều client.
Ví dụ: một Stateless Session Bean thực hiện việc đăng ký để kiểm tra người dùng và password, cho phép người dùng tạo một account trong hệ thống. Có remote interface như sau:
public interface SignOn extends EJBObject {
public void addUser( String username, String password ) throws RemoteException;
public boolean validateUser( String login, String password )
throws InvalidLoginException, RemoteException;
}
•Stateful Session Bean: (bean lưu vết) lưu trạng thái conversation của server với client cụ thể trong các field của nó. Trạng thái conversation này sẽ được lưu trữ xuyên qua nhiều yêu cầu của client trong cùng một session.
Ví dụ: một Steless Session Bean dùng mô phỏng phiếu đăng ký các môn học được chọn bởi một sinh viên cụ thể trong một session chọn khóa học. Có remote interface như sau:
public interface EnrollmentCart extends EJBObject {
public void addCourses( String[] courseIds ) throws RemoteException;
public Collection getCourses() throws RemoteException;
public void empty() throws RemoteException;
}
dữ liệu đăng ký (trạng thái conversation) sẽ được lưu trong một field của lớp bean.
public class EnrollmentCartEJB implements SessionBean {
...
private HashSet cart;
...
public void addCourses( String[] courseIds ) {
if ( courseIds == null ) return;
for ( int i = 0; i < courseIds.length ; ++i ) cart.add( courseIds );
}
public void empty() { cart.clear(); }
}
Monday, 20. April 2009, 15:08:31
Các cách cài đặt ứng dụng phân tán
Sockets DCOM( Distributed Component Object Model RPC ( Remote Procedure Call) CORBA (Common Object Request Broker Architechture – OMG) Java RMI Khái niệm - RMI cung cấp khả năng triệu gọi các phương thức của một đối tượng từ xa thông qua giao thức JRMP. Bằng cách này có thể liên lạc và thực thi các ứng dụng xuyên qua nhiều hệ thống trên một mạng. - RMI được hỗ trợ bởi các gói java.rmi, java.rmi.server, java.rmi.registry. - Java 2 yêu cầu cài đặt một chính sách bảo mật khi thực hiện RMI. Cách tiếp cận Chương trình server /đối tượng chạy trên một JVM khác với chương trình gọi (client) Không gian địa chỉ khác nhau Phương cách cài đặt : Định nghĩa các phương thức interface Cài đặt các phương thức này class
Thành phần của 1 hệ thống RMI Định nghĩa các giao diện cho các phương thức triệu gọi từ xa (remote interface). Cài đặt đối tượng cho việc triệu gọi phương thức từ xa (remote object). Các file Stub và Skeleton. Một server đặt(host) đối tượng truy xuất từ xa. Một dịch vụ RMI Naming cho phép client định vị được đối tượng truy xuất từ xa. Các lớp hỗ trợ nếu có. Stub Stub đại diện cho đối tượng remote ở phía client, có nhiệm vụ: Khởi tạo một lời gọi đến remote object, bằng cách gọi remote refererence layer. Sắp xếp (marshaling) các đối số cần chuyển thành một stream tuần tự nhờ remote reference layer. Báo cho remote reference layer lời gọi đã được triệu gọi. Lấy (unmarshaling) trị trả về hoặc exception từ stream tuần tự. Báo cho remote reference layer lời gọi đã được hoàn thành Skeleton Skeleton là một thực thể phía server chứa một phương thức chuyển các lời gọi đến remote object thật sự. Có nhiệm vụ: Lấy (unmarshaling) đối số từ stream tuần tự. Tạo một lời gọi (up-call) đến remote object cài đặt thật sự. Sắp xếp (marshaling) trị trả về hoặc exception thành một stream tuần tự, nhờ remote reference layer. Remote Interface Remote interface có nhiệm vụ bộc lộ các phương thức của đối tượng server để client có thể triệu gọi từ xa (triệu gọi từ JVM khác). Các yêu cầu của remote interface: Phải được khai báo public để client có thể “nhìn thấy” các phương thức khai báo trong interface, vì client thường không cùng gói với remote interface. Thừa kế giao diện java.rmi.Remote. Các phương thức triệu gọi từ xa phải ném (throws) ra exception java.rmi.RemoteException khi gặp các lỗi kết nối mạng hoặc lỗi server. Remote Interface Example import java.rmi.*; public interface Adder extends Remote { public int add(int x, int y) throws RemoteException; } Remote Class Example import java.rmi.*; import java.rmi.server.*; public class AdderImpl extends UnicastRemoteObject implements Adder { public AdderImpl() throws RemoteException { } public int add(int x, int y) throws RemoteException { return x + y; } } RMI Registry Client phải “định vị” được đối tượng remote để triệu gọi từ xa các phương thức, điều này được thực hiện dưới sự hỗ trợ của dịch vụ Remote Object Registry (RMI Registry). RMI Registry là dịch vụ đặt tên Naming, cho phép đăng ký đối tượng remote dưới một tên, sau đó client có thể nhận tham chiếu đến đối tượng remote thông qua tên đã đăng ký Naming.rebind(“rmi://localhost:1099/adder", adder); RMI Server try { AdderImpl adder = new AdderImpl(); Naming.rebind(“rmi://localhost:2000/aaa", adder); System.out.println("Adder bound"); } catch (RemoteException re) { re.printStackTrace(); } catch (MalformedURLException me) { me.printStackTrace(); } RMI Client // dùng interface lấy tham chiếu remote Object Adder a = (Adder) Naming.lookup(“rmi://localhost:2000/aaa"); // tìm thấy và thi hành phương thức int sum = a.add(2,2); System.out.println("2+2=" + sum); Câu hỏi 1. COM là gì DCOM ? 2. Thế nào là Java RMI 3. Ích lợi của RMI 4. Các thành phần chính của một hệ thống RMI 5. Các bước cài đặt 1 hệ thống RMI
Monday, 20. April 2009, 14:34:42
1.Giới thiệu: Hãy tưởng tượng xem khi bạn đang thực hiện một đề án lớn bằng Java, nó bao gồm nhiều tập tin java và những lớp (class) phụ thuộc vào những lớp khác hay những lớp stub hoặc driver chẳng hạn. Chúng được chứa trong nhiều thư mục khác nhau, và kết quả thu được cũng cần đặt trong nhiều thư mục … và kết quả là bạn phải dùng những công cụ biên dịch và phải tự mình thao tác tất cả, và tất nhiên điều đó sẽ làm cho bạn mất hàng giờ để thực hiện việc đó. Vậy tại sao ta không phát triển một chương trình có thể thực hiện được những việc mà chúng ta cần và công cụ đó chính là ANT ( Bạn có thể tham khảo thêm tại website http://jakarta.apache.org/ant/ ). ANT ( Another Neat Tool ), là công cụ xây dựng hỗ trợ đặc biệt cho lập trình bằng Java nhưng cũng có thể sử dụng cho nhiều thứ khác, vì đây là công cụ được viết hoàn toàn bằng Java nên không phụ thuộc vào bất cứ nền ứng dụng nào. Ant rất hữu ích trong công việc phức tạp đòi hỏi phải lập đi lập lại nhiều lần, vì vậy nên thích hợp với việc xử lý một cách tự động và được chuẩn hóa. Ant dùng định dạng XML để làm cơ chế hoạt động cho công cụ dưới dạng những lời hướng dẫn ( instructions), do đó dễ dàng mở rộng và bảo trì. 2.Cài đặt: -Tải công cụ Ant từ địa chỉ sau : http://jakarta.apache.org/ant/index.html, sau đó giải nén vào một thư mục. -Thêm đường dẫn đến thư mục /bin trong thư mục đã giải nén vào biến môi trường PATH. -Thêm vào biến môi trường CLASSPATH đường dẫn đến những tập tin .jar trong thư mục /lib trong thư mục giải nén. (để biết thêm chi tiết xin xem thêm tại thư mục /docs/manual/install.html ) - 3.Cơ bản: Tập tin xây dựng Ant được viết dưới dạng XML, nên chỉ cần có một phần mềm soạn thảo văn bản là có thể xây dựng tập tin Ant. Sau đây là ví dụ đơn giản: Ví dụ 1 : build.xml <?xml version="1.0"?> <project name="test" default="compile" basedir="."> <property name="src" value="."/> <property name="build" value="build"/> <target name="init"> <mkdir dir="${build}"/> </target> <target name="compile" depends="init"> <!- - Compile the java code - -> <javac srcdir="${src}" destdir="${build}"/> </target> </project> Mô tả: <?xml version="1.0"?> Vì đây là tập tin xml nên luôn được bắt đầu bằng thẻ này. <project name="test" default="compile" basedir="."> Thẻ gốc (root element) của tập tin Ant là <project>, nó có 3 thuộc tính sau: -name: đây là tên của của đề tài -default: mục này chỉ định thẻ <target> mặc định khi không có thẻ <target> nào được chỉ định, đây là thuộc tính bắt buộc phải có. -basedir: chỉ định thư mục gốc mà bên trong tập tin Ant tham chiếu đến, nếu mục này bị bỏ qua thì thư mục hiện hành chứa tập tin Ant sẽ được sử dụng. <property name="src" value="."/> <property name="build" value="build"/> Thẻ property cho phép khai báo biến để sử dụng trong tập tin Ant, thuộc tính name dùng đặt tên cho biến, và thuộc tính value chứa giá trị của biến đó. Để tham chiếu đến giá trị của biến này ta dùng cú pháp sau ${name-property}, như trong ví dụ trên để tham chiếu đến biến src ta dùng như sau ${src} <target name="init"> <mkdir dir="${build}"/> </target> Thẻ <target> dùng để bao bọc một nhóm các hành động, mỗi thẻ có một tên để có thể tham chiếu đến ở bất kì đâu, có thể từ bên ngoài dưới dạng dòng lệnh, hay từ bên trong thông qua từ khoá depends, hoặc có thể từ một lời gọi trực tiếp. Trong ví dụ trên ta có thẻ <target> đặt tên là “init”, nó sẽ tạo ra một thư mục bằng cách sử dụng thẻ <mkdir> với tên được chỉ định bởi biến build đã được khai báo ở trên Thẻ <target> có những thuộc tính sau: -name: đặt tên cho thẻ để có thể tham chiếu đến sau này, thuộc tính này bắt buộc phải có -depends: đây là một danh sách chứa các target khác mà thẻ target này phụ thuộc, các target được phân cách bằng dấu phẩy, các target nằm trong danh sách này phải được thực thi trước thẻ <target> này. -if: cho phép thêm điều kiện để xét xem có thực hiện các hành động trong thẻ <target> không dựa trên giá trị của biến. Ví dụ if=”dk” ta có thể hiểu như sau: nếu biến dk được gán giá trị bất kì thì sẽ thực hiện các hành động trong thẻ <target>. -unless: thuộc tính này ngược lại với if -description: dùng để mô tả ngắn gọn cho thẻ <target> <target name="compile" depends="init"> <!- - Compile the java code - -> <javac srcdir="${src}" destdir="${build}"/> </target> Như đã mô tả ở trên, vì thuộc tính depends=”init” nên thẻ <target> này phải được thực thi sau khi thẻ target có tên là “init” được thực thi. Ta thấy có thẻ javac được sử dụng trong ví dụ trên, thẻ này có thể hiểu như một nhiệm vụ, những nhiệm vụ cần thực hiện được lồng trong thẻ target. Trong trường hợp này thư mục chứa mã nguồn (srcdir) được gán bằng biến src mà ta đã khai báo và thư mục đích mà ta cần xuất kết quả ra (destdir) được gán bằng biến build, và khi target thực thi thì javac sẽ biên dịch các tập tin java trong thư mục srcdir (tham chiếu đến biến src) và trả về kết quả là các tập tin class được đặt trong thư mục destdir (tham chiếu đến biến build). Ngoài lệnh javax ra, ant còn hỗ trợ lệnh java để thực thi chương trình. Sau khi hiểu rõ những tính năng của từng thẻ, hãy thực hiện ví dụ trên theo các bước sau: -Chép mã nguồn ở ví dụ trên và lưu lại thành tập tin build.xml vào thư mục test -Tạo một file java với nội dung bất kì ví dụ như sau: public class test { public static void main(String[] args) { System.out.println("Hello World!"); } } -Lưu tập tin java trên vào chung thư mục test -Sau đó chạy dòng lệnh : ant –v -Dòng lệnh này sẽ thực thi theo hướng dẫn trong tập tin build.xml, nó sẽ tạo ra thư mục build chứa tập tin class được biên dịch từ tập tin java. Tham số –v sẽ hiển thị thông tin trong quá trình lệnh ant thực thi (các tham số của lệnh ant tham khảo thêm tại phụ lục A). 4.Mô tả chi tiết về một đề án đặc trưng: Khi bắt đầu tiến hành một đề án, thông thường ta sẽ tạo ra những thư mục sau : -src: chứa các tập tin mã nguồn -build: chứa các tập tin trả về sau khi biên dịch -lib: chứa các tập tin dùng làm thư viện cho chương trình Bây giờ ta sẽ tiến hành các bước sau để sử dụng Ant: -Đầu tiên tạo tập tin AntDemo.java với nội dung như sau: import javax.swing.*; import java.awt.*; public class AntDemo extends JFrame { public AntDemo() { super("Ant Demo"); ImageIcon icon = new ImageIcon("image.jpeg"); getContentPane().add(new JLabel(icon)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setVisible(true); } public static void main(String args[]) { new AntDemo(); } } -Tạo 3 thư mục src, build, lib trong thư mục test ta đã tạo ở trên, sau đó lưu tập tin AntDemo.java và image.jpeg vào thư mục src -Bước tiếp theo ta sẽ tạo tập tin build.xml với nội dung như sau: <?xml version="1.0"?> <project name="AntDemo" default="all" basedir="."> <property name="src" value="src"/> <property name="build" value="build"/> <property name="lib" value="lib"/> <target name="all" depends="AntDemo" description="Builds the whole project"> <echo>Doing all</echo> </target> <target name="AntDemo" description="Builds the main AntDemo project"> <echo>Doing AntDemo</echo> <copy file="${src}/image.jpeg" tofile="${build}/image.jpeg"/> <javac srcdir="${src}" destdir="${build}"/> </target> </project> -Lưu tập tin build.xml vào thư mục test, và chạy ant như phần trên. Kết quả thu được là: Buildfile: build.xml AntDemo: [echo] Doing AntDemo [copy] Copying 1 file to C:\docbook\docproj\src\items\ant\files\build [javac] Compiling 1 source file to \blah\blah\blah\build all: [echo] Doing all BUILD SUCCESSFUL Total time: 2 seconds Lưu ý: nếu muốn sử dụng các tham số trong câu lệnh java như : javac –v –listfiles … ta sẽ làm bằng cách gán cho các thuộc tính đó giá trị bằng “true”, ví dụ như muốn trong quá trình biên dịch muốn hiển thị danh sách các tập tin được biên dịch ta thêm vào thẻ javac ở trên thuộc tính sau: listfiles=”true”. Trong ví dụ trên có một thẻ mới đó là thẻ <copy> , dùng để sao chép các tập tin vào các thư mục cần thiết, với thuộc tính srcdir chỉ định thư mục đang chứa tập tin cần sao chép, destdir chỉ định thư mục cần sao chép đến. Mặc định, ant chỉ sao chép lại những tập tin đã sao chép rồi khi chúng được thay đổi, nếu muốn ant luôn sao chép mỗi khi thực thi thì ta sẽ gán giá trị “true” cho thuộc tính overwrite cho thẻ copy. Thẻ <echo> sẽ in nội dung ra màn hình thực thi. Để hiểu rõ hơn ta sửa lại nội dung của tập tin AntDemo.java như sau: public AntDemo() { super("AntDemo"); ImageIcon icon = new ImageIcon("image.jpeg"); JButton exitButton = new JButton("Exit"); exitButton.addActionListener(new ExitControl()); JButton aboutButton = new JButton("About"); aboutButton.addActionListener(new AboutControl()); getContentPane().setLayout(new FlowLayout()); getContentPane().add(new JLabel(icon)); getContentPane().add(aboutButton); getContentPane().add(exitButton); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setVisible(true); } Tiếp theo, tạo tập tin ExitControl.java với nội dung sau: import java.awt.event.*; public class ExitControl implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } } Tạo tập tin AboutControl.java: import java.awt.event.*; public class AboutControl implements ActionListener { public void actionPerformed(ActionEvent e) { new AboutPopup(); } } Tạo tập tin AboutPopup.java: import javax.swing.*; import java.awt.*; public class AboutPopup extends JFrame { public AboutPopup() { super("About"); String message = "\n"; message+="Bye bye world ???"; setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setSize(new Dimension(300,300)); JTextPane messagePane = new JTextPane(); messagePane.setBackground(Color.BLACK); messagePane.setForeground(Color.GRAY); messagePane.setEditable(false); messagePane.setText(message); getContentPane().add(messagePane); setResizable(false); setVisible(true); } } Lưu tất cả các tập tin java vào thư mục src và sửa đổi lại tập tin build.xml như sau: -Ở phần thẻ target AntDemo: <target name="AntDemo" depends="AboutControl,ExitControl" description="Builds the main AntDemo project"> <echo>Doing AntDemo</echo> <copy file="${src}/image.jpeg" tofile="${build}/image.jpeg"/> <javac srcdir="${src}" destdir="${build}" includes="AntDemo.java"/> </target> Ta đã thêm vào depends="AboutControl,ExitControl" để báo cho ant biết rằng thẻ target này sẽ được thực thi sau khi thẻ target có tên AboutControl và ExitControl được thực thi. Ngoài ra trong thẻ javac có thêm thuộc tính includes để chỉ ra cho ant biết tập tin nào cần được biên dịch, trong ví dụ trên ta báo cho ant biết rằng chỉ biên dịch tập tin AntDemo.java trong thư mục được chỉ định trong thuộc tính srcdir. Giá trị của includes có thể là danh sách các tập tin cần được biên dịch, nếu bỏ qua includes thì ant sẽ biên dịch tất cả. -Vì thẻ target AntDemo có thuộc tính depends=”AboutControl,ExitControl” nên ta sẽ thêm vào 2 thẻ target mới với tên tương ứng như sau: <target name="AboutControl" depends="AboutPopup" description="Builds AboutControl"> <echo>Doing AboutControl</echo> <javac srcdir="${src}" destdir="${build}" includes="AboutControl.java"/> </target> <target name="ExitControl" description="Builds ExitControl"> <echo>Doing ExitControl</echo> <javac srcdir="${src}" destdir="${build}" includes="ExitControl.java"/> </target> Thẻ target AboutControl có thuộc tính depends=”AboutPopup” để chỉ ra rằng thẻ target này sẽ được thực thi sau khi thẻ target AboutPopup được thực thi. Vì thế ta sẽ tạo thêm thẻ target có tên là AboutPopup như sau: <target name="AboutPopup" description="Builds AboutPopup"> <echo>Doing AboutPopup</echo> <javac srcdir="${src}" destdir="${build}" includes="AboutPopup.java"/> </target> -Cuối cùng ta sẽ thêm vào thẻ target Clean, được dùng để xoá tập tin trong thư mục được chỉ định như sau: <target name="Clean" description="Removes previous build"> <delete verbose="true"> <fileset dir="${build}"/> </delete> </target> Trong thẻ target trên ta có thẻ <delete> để chỉ ra rằng ta muốn xoá, thuộc tính verbose=”true” sẽ in ra danh sách các tập tin được xóa khi thực thi thẻ target. Thẻ <fileset> dùng để chỉ ra thư mục chứa các tập tin cần xóa với thuộc tính dir chứa đường dẫn đến thư mục đó. Nếu muốn xóa cả thư mục đó thì gán giá trị “true” cho thuộc tính includeEmptyDirs. (tham khảo thêm về thẻ fileset trong phần phụ lục B) Để xoá các tập tin đã biên dịch trước kia, ta chạy lệnh sau: ant Clean Kết quả như sau: Buildfile: build.xml Clean: [delete] Deleting 2 files from \blah\blah\build [delete] Deleting \blah\blah\blah\build\AntDemo.class [delete] Deleting \blah\blah\blah\build\image.jpeg BUILD SUCCESSFUL Total time: 1 second Tiếp theo ta sẽ thực thi lệnh ant không cần tham số nào cả, do đó ant sẽ thực thi thẻ target được quy định trong thuộc tính default được nêu ở trên Kết quả như sau: Buildfile: build.xml AboutPopup: [echo] Doing AboutPopup [javac] Compiling 1 source file to \blah\blah\blah\build AboutControl: [echo] Doing AboutControl [javac] Compiling 1 source file to \blah\blah\blah\build ExitControl: [echo] Doing ExitControl [javac] Compiling 1 source file to \blah\blah\blah\build AntDemo: [echo] Doing AntDemo [copy] Copying 1 file to \blah\blah\blah\build [javac] Compiling 1 source file to \blah\blah\blah\build all: [echo] Doing all BUILD SUCCESSFUL Total time: 4 seconds Có thể thấy được các thẻ target được thực thi theo thứ tự được quy định bởi thuộc tính depends trong các thẻ target. 5.Nâng cao: Để hỗ trợ cho việc điều khiển sự lưu thông (flow of control) của tiến trình, ant cung cấp cú pháp gọi những thẻ <target> khác bằng cú pháp sau: <antcall target=”target-name”> Giả sử ta muốn tiến trình thực hiện theo cú pháp trong Java như sau: if( condition ) { if( inner-condition ) { A } else { B } } else { C } Trong ant ta có thể viết như sau: <?xml version="1.0"?> <project name="Flow.Of.Control" default="nested-if" basedir="."> <target name="nested-if"> <condition property="condition"> <available file="fileone"/> </condition> <antcall target="then"/> <antcall target="else"/> </target> <target name="then" if="condition"> <echo>THEN BODY EXECUTED</echo> <condition property="inner-condition"> <available file="filetwo"/> </condition> <antcall target="inner.then"/> <antcall target="inner.else"/> </target> <target name="inner.then" if="inner-condition"> <echo>INNER THEN BODY EXECUTED</echo> </target> <target name="inner.else" unless="inner-condition"> <echo>INNER ELSE BODY EXECUTED</echo> </target> <target name="else" unless="condition"> <echo>ELSE BODY EXECUTED</echo> </target> </project> Trong cú pháp trên, ta sử dụng thuộc tính if và unless để xét điều kiện, đầu tiên “nested-if” được gọi, nó sẽ kiểm tra xem tập tin có tên “fileone” có tồn tại hay không, nếu tồn tại thì biến condition sẽ được gán giá trị, sau đó gọi thẻ target “then” và thẻ target “else”. Khi thẻ target “then” được gọi, nó sẽ kiểm tra điều kiện thông qua biến property có tên là “condition”, nếu biến này được gán giá trị thì sẽ thực hiện các hành động trong thẻ target này. Trong thẻ target “then” lại xét xem tập tin “filetwo” có tồn tại hay không, nếu tồn tại thì biến inner-condition sẽ được gán giá trị, sau đó gọi thẻ target “inner.then” và thẻ target “inner.else”. Quá trình trên có thể được mô tả bằng sơ đồ sau: Phụ lục A Tham sốMô tả -vHiển thị thông tin trong quá trình thực thi ant -projecthelpHiển thị thông tin về các thẻ target hiện có trong tập tin build.xml Phụ lục B FileSet được dùng như một bộ lọc để chỉ ra những tập tin thoả mãn những điều kiện nào đó bằng cách dùng một hay nhiều mẫu được chỉ định. FileList là danh sách những tập tin thoả mãn điều kiện, FileSet dùng PatternSets và Patterns để định nghĩa những hành động cần thực hiện. -dấu ? đại diện cho 1 kí tự bất kì -dấu * đại diện cho nhiều kí tự bất kì hay không có kí tự nào cả -dấu ** đại diện cho nhiều thư mục bất kì hay không có thư mục nào cả Fileset phải chỉ định thư mục gốc (Base directory) thông qua thuộc tính dir, để từ đó tính toán các đường dẫn có liên quan. <fileset dir="BASEDIR"/> Hay: <fileset dir="BASEDIR"> </fileset> Ví du 1: <fileset. dir="." includes="**/*.blah **/*.bleh" Trong ví dụ trên, bao gồm tất cả các tập tin có đuôi là .blah hay .bleh trong thư mục hiện tại và trong các thư mục con của thư mục hiện tại. Ví dụ 2: <fileset. dir="."> <include. name="**/*bl*"/> <exclude name="**/blah/*"/> </fileset> Ta có thể viết cú pháp như trên để chỉ ra rằng sẽ bao gồm tất cả các tập tin có tên chứa chuỗi “bl” trong thư mục hiện tại và trong các thư mục con. Và sẽ loại bỏ những tập tin nằm trong thư mục có tên “blah” trong thư mục hiện tại hay trong các thư mục con. Chú ý rằng ta sử dụng thẻ <include> và thẻ <exclude> với thuộc tính name thay vì dùng thuộc tính includes và excludes trong thẻ <fileset> Vậy khi ta cần dùng nhiều lần 1 mẫu (pattern) nào đó lại phải viết lại nhiều lần chăng, câu trả lời đó là dùng thẻ <patternset> với cú pháp sau: <fileset dir="."> <patternset id="blah"> <include name="**/*bl*"/> <exclude name="**/blah/*"/> </patternset> </fileset> Sau khi khai báo thuộc tính id của thẻ patternset, nếu sau này cần dùng đến ta chỉ cần tham chiếu đến thẻ patternset trên với cú pháp sau: <fileset dir="."> <patterset refid="blah"/> </fileset> Ta cũng có thể dùng thuộc tính if và unless trong thẻ include và exclude để đưa ra điều kiện thêm vào (include) hay bỏ đi (exclude). Ví dụ 3: <fileset dir="."> <include name="**/extensions/*.java" if="version.professional"/> </fileset> Trong ví dụ này chỉ ra rằng sẽ bao gồm tất cả tập tin .java trong thư mục extensions nếu biến version.professional được gán giá trị bất kì. Ví dụ 4: <fileset dir="."> <exclude name="chinese.lang" unless="language.chinese"/> </fileset> Trong ví dụ này sẽ loại bỏ tập tin chinese.lang nếu biến language.chinese không được gán giá trị nào cả. Ngoài ra, nếu như giá trị của thuộc tính name của thẻ include hay exclude quá nhiều ta có thể tạo danh sách các tập tin trong một tập tin khác và tham chiếu đến tập tin đó bằng bằng thẻ <includesfile>,<excludesfile> với cú pháp sau: <fileset dir="."> <includesfile name="some.file"/> </fileset> Tập tin some.file có thể có nội dung như sau: bl?h.bl?h *.java FileList: tương tự FileSet nhưng không hỗ trợ những kí tự đại diện ? và *. Ta phải liệt kê hết những tập tin ngăn cách nhau bởi dấu phẩy hay khoảng trắng trong thuộc tính files.Và ta cũng có thể đặt id và tham chiếu đến FileList đó thông qua thuộc tính refid như sau: <filelist id="blah" dir="." files="blah.blah bleh.bleh"/> Tham chiếu đến FileList: <filelist refid="blah"/>
Monday, 20. April 2009, 13:03:43
SESSION – KHÁI NIỆM
HTTP là một stateless protocol. Session tracking là cơ chế để hỗ trợ việc lưu trữ thông tin trạng thái qua các thành phần của Servlet API. Session là cách giải quyết việc lưu trữ thông tin – trạng thái trong Web application. Session hỗ trợ Web Server phân biệt các users khác nhau. Session được thiết kế như thành phần của Server giải quyết stateless theo 03 cách Cookies URL – Writing Hidden form fields Session được khởi tạo khi user truy cập hay login vào trang Web. Thời gian tồn tại của Session: Đóng Web browser. Logout khỏi ứng dụng Web. Time out.COOKIES
Cookies là các thông tin text đơn giản để Web server gửi tới browser. Các request trong lần tiếp theo sẽ đính kèm cookies. Server dùng cookies để sử dụng các thông tin của clients. Mỗi browser có thể chứa 20 cookies/ site và tối đa là 300 cookies. Kích thước tối đa của cookies là 4Kb. Mỗi Cookies có 01 SessionID tương ứng. Ưu điểm Xác nhận user trong suốt quá trình giao dịch điện tử Hỗ trợ việc checkLogin (low security) Hỗ trợ việc cung cấp thông tin ưa thích cho người dùng Hỗ trợ cho việc quảng cáo trên trang web.Có tính bảo mật Nhược điểm Xâm phạm tự do riêng tư Gây ra các spam về mail và trang web. Browser phải hỗ trợ hay cho phép cookies.Kích thước giới hạn.SERVLET COOKIES
Tạo cookies bằng cách gọi Cookies constructor Các phương thức API hỗ trợ get/setVersion (chuỗi): version của protocol Cookies int get/setMaxAge(int):thời gian cookies expires (s) String get/setName(tên cookies) String get/setPath(String path): đường dẫn chứa cookies. “/” tất cả trang String get/setValue(String):các giá trị kết hợp với cookies response.addCookies: insert cookies request.getCookies: đọc cookies từ client
VÍ DỤ Lưu cookies trên máy và hiển thị thông tin <%@ page import="javax.servlet.http.Cookie" %> <html.> <head.> <title.>Cookies Demo</title.> </head.> <body.> <h1.>Cookies</h1.> <% Cookie[] allCookies = request.getCookies(); Cookie ourCookie=null; if(allCookies!=null){for(int i=0; i<allCookies.length; i++) { if(allCookies.getName().equals("TestCookies")) { ourCookie = allCookies; }}} if(ourCookie==null){ Cookie cookie=new Cookie("TestCookies", "welcome Cookie"); cookie.setPath("/"); response.addCookie(cookie);%> A cookie has beean added to your machine! Select refresh to see the details of the cookie. <% } else {%> The following cookie was added earlier to your machine: Version: <%= ourCookie.getVersion() %> Name: <%= ourCookie.getName() %> Value: <%= ourCookie.getValue() %> MaxAge: <%= ourCookie.getMaxAge() %> <% } %> </body.> </html.>
SESSION TRACKING in SERVLETS Servlet cung cấp một nơi để lưu trữ các thông tin cần thiết về session. Session Tracking: Xác định đối tượng HttpSession có liên quan đến request hiện hành: Sử dụng phương thức getSession của HttpServletRequest Hệ thống thực hiện trích xuất userID từ cookie hay dữ liệu attach trong URL để tạo ra đối tương HttpSession Xác định xem user đã tồn tại hay chưa? Nếu chưa tồn tại thì thực hiện tạo mới dùng phương thức getSession(true). HttpSession tồn tại trên server và cho phép lưu trữ key và các giá trị Ví dụ: HttpSession session = request.getSession(true); Session Tracking (tt) Tìm kiếm và thiết lập các thông tin trong Session Sử dụng phương thức (Object) session.getValue(“tên thuộc tính”) (2.1) hay session.getAttribute(“tên thuộc tính”) (2.2) để lấy giá trị của thuộc tính lưu trữ. Sử dụng phương thức (String[]) session.getValueNames() hay session.getAttributeNames() để lấy tất cả tên thuộc tính có trong Session Các phương thức hỗ trợ khác setAttribute – putValue(“tên thuộc tính”, giá trị) removeAttribute – removeValue(“tên thuộc tính”) String getId() boolean isNew(): false nếu tồn tại Session long getCreateTime() hay long getLastAccessedTime() int getMaxInactiveInterval() và setMaxInactiveInterval(int seconds) VÍ DỤ Servlet resp.setContentType("text/html"); PrintWriter pw=resp.getWriter(); pw.println("<html><head>Cart </head><body>"); HttpSession session=req.getSession(true); CartBean shoppingCart=(CartBean)session.getAttribute("cart"); if(shoppingCart==null){ shoppingCart=new CartBean();} String action=req.getParameter("mode"); String bookTitle=req.getParameter("lstBook"); if(action.equals("add")){ shoppingCart.addBook(bookTitle); RequestDispatcher rd=getServletContext().getRequestDispatcher("/"); rd.forward(req, resp);} if(action.equals("view")){ int count=0; String booktitle; pw.println("Your Cart contents:
"); Vector bookList=shoppingCart.getContents(); Enumeration item=bookList.elements(); pw.println("<form action='CartServlet?mode=remove' method='post'>"); pw.println( "<table border='1' cellpadding='2' cellspacing='0' width='395' " ); pw.println( "bordercolor='#666666' style='border-collapse: collapse'>" ); pw.println( " " ); while(item.hasMoreElements()){ ++count; booktitle=(String)item.nextElement(); pw.println( "" ); pw.println( "Order " ); pw.println( "" ); pw.println( "Books title " ); pw.println( "" ); pw.println( "Action " ); pw.println( "" );} pw.println( " " + count + " " ); pw.println( "" + booktitle + " "); pw.println( "" ); pw.println( "<input type='checkbox' name='rmv' value='" + booktitle + "'> </table.></form.>" );} if(action.equals("remove")){ String title[]=req.getParameterValues("rmv"); if(title==null){ title=new String[0];} try{ for(int i=0; i<title.length; i++) { shoppingCart.removeBook(title);}}catch(Exception e){} RequestDispatcher rd=getServletContext().getRequestDispatcher("/CartServlet?mode=view"); rd.forward(req, resp);} session.setAttribute("cart", shoppingCart); pw.println("</body.></html.>"); pw.close(); " ); pw.println( "Choose next" ); pw.println( " <input. type='submit' value='Remove'>
Monday, 20. April 2009, 12:49:24
Welcome to JSP course
"); out.println("</body></html>");} public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ doGet(request, response);}}Monday, 20. April 2009, 12:19:09
Monday, 20. April 2009, 10:52:02
Showing posts 1 - 10 of 12.
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
|
| ||||||
| 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 | |||