Ứng dụng RMI
0 Để kết thúc chương trình này chúng ta hãy xây dựng 1 ứng dụng RMI có ích thực sư. Chương trình của ta có chức năng cung cấp và hiển thị giá cổ phiếu của các công ty máy tính lớn hiện nay như ...
Để kết thúc chương trình này chúng ta hãy xây dựng 1 ứng dụng RMI có ích thực sư. Chương trình của ta có chức năng cung cấp và hiển thị giá cổ phiếu của các công ty máy tính lớn hiện nay như : Microsof , IBM , Sun .... Cơ chế hoạt của chương trình dựa vào mô hình phân tán đối tượng và ký thuật gọi hàm từ xa RMI
Bạn hãy hình dung chúng ta có 1 đối tượng ở xa chịu trách nhiệm cung cấp giá cổ phiếu hiện hành của tất cả công ti trên thế giới . Máy khách là 1 chương tring Applet chạy trên trình duyệt Browse . Applet sẽ gửi yêu cầu đến đối tượng chủ yêu cầu mối giây phảI cập nhật lại giá để trình khách ( Applet) có thể hiển thị thông báo đến người mua cổ phiếu . Với phác thảo như trên bạn thấy chương trình của chúng ta gàn giống với chương trình mấu CallBack ở ví dụ 2-15 . Vâng , đúng là chúng ta sẽ thiết kế chương trình ở dạng máy chủ có thể tham chiếu ngược về đối tượng trên máy khách ( CallBack). Ví dụ 2-15 chỉ là 1 mô hình mẫu đơn giản . Thiết kế 1 ứng dụng thực thụ đòi hỏi chúng ta phải xây dựng 1 giao diện Applet ở phía máy khách đổng thời tính toán chính xác thời gian để gửi dữ liêuk từ máy chủ về cho máy khách ở xa .Hình 2-12 là cơ chế giao tiếp giữa trình khách và đối tượng trên máy chủ .

Chúng ta sẽ lần lượt xây dựng chương trình qua các bước sau :
Bước 1 : đầu tiên bạn hình dung chúng ta cần tạo 1 đối tượng có khả năng chuyển thông tin qua lại giữa trình khách và trình chủ , Chúng ta gọi đối tượng này là Stock .
Đối tượng Stock chứa thông tin về giá cổ phiếu và tên của công ty bán ra cổ phiếu đó. Stock được cài đặt như sau :
Ví dụ : Stock Java.until.* ;
// **
* Đối tượng Stock dùng để chứa thông tin cập nhật từ máy chủ gửi về. Do phảI di chuyển trên mạng nên lớp Stock cần cài đặt giao tiếp Java.io.Serializable . Khi đó trong các lời gọi hàm RMI Stock sẽ được truyền theo trị.
* /
Public Class Stock implement Java.io.Serializable {
String symbol ;
Float current;
Private static random random = new random ();
Private final static float MAX_ VALUE = 67;
/**
- Tạo đối tượng Stock dựa vào tên của công ty và chọn ngẫu nhiên giá cổ phiếu cho công ty đó
* /
Public Stock (String name) {
Symbol = name;
// Tạo giá cổ phiếu ngẫu nhiên trong khoảng từ 20-60
Current = (float)(Math.abs (Random.nextInt()) %40+20);
}
/**
- Cập nhật lại thay đổi của giá cổ phiếu
*/
Public float update () {
Float change = (( float)(Random.nextGaussion() * 1.0));
Change = Math.abs(change); // Thay đổi này tùy bạn quyết định
Float newCurrent = Current + Change;
// Không cho phép giá cổ phiếu vượt qua mức trần
If (newCurrent < 0 | | newCurrent > MAX_VALUE)
Change = 0 ;
Current + = change;
Return change;
}
}
Chúng ta sử dụng đối tượng Random của gói Java.until để tạo số ngẫu nhiên mô phỏng sự biến động giá cổ phiếu. Phương thức update () trong Stock dùng để lấy về thay đổi giá cổ phiếu của 1 công ty. Trên thực tế bạn có thể thiết kế hàm update() dựa vào cơ sở dữ liệu hoặc lấy thông tin từ thị trường chứng khoán.
Bước 2 : Đặc tả giao tiếp của đối tượng StockNotify là một đối tượng có khả năng tham chiếu xa , Nó giúp cho trình chủ có thể chủ động gọi ngược và truyền thông tin về trình khách ( Bạn xem lai ký thuât CallBack ở mục 7-4 )
Ví dụ : StockNotify,java
Import java.rmi.*;
Import java.Util,* ;
/ **
- StockNotify dùng để nhận các thông tin cập nhật về giá trị cố phiếu do đối tượng trên máy chủ tạo ra
*/
Public interface StockNotify extends Java.rmi.Remote {
/**
- Trình chủ sẽ gọi phương thức update() này ngay trên máy chủ để truyển thông tin về cho trình khách
- Date thời gian mới nhất giá cổ phiều được cập nhật
- Stocks Danh sách cổ phiếu của các công ty đã dăng ký với trình chủ yêu cầu cập nhật
* /
Void Update( Date date , Stock [ ] Stocks) throws RemoteExce ption ;
}
Máy khách sẽ thực hiện danh sách các cổ phiếu cần cập nhật . Đối tượng chủ sẽ dựa vào danh sách này để gửi giá cổ phiếu về cho máy khách cùng với thời gian cập nhật sớm nhất .( Chúng ta sẽ thực hien cài đặt cho đối tượng StockNotify chung với trình khách Applet ở bước 5).
Bước 3: Đặc tả giao tiếp của đối tượng chủ .
Ví dụ : StockWatch. Java
Import java.rmi.*;
/**
- Đối tượng StockWatch dùng để tiếp nhận đăng ký đối tượng StockNotify từ trình khách . Đồng thời cập nhật giá cổ phiếu cho trình khách định kỳ
*/
Public interface StockWatch extends java.rmi.Remote {
/**
- Tiếp nhận tham chiếu đến đối tượng StockNotify trên máy khách
- Stock Tên cổ phiếu
- Obj Đối tượng StockNotify cập nhật trình khách
- Trả về giá cố phiếu mới nhất
*/
Public StockWatch (St ring stock. StockNotify Obj ) throws RemoteException;
/**
- Hủy bỏ yêu cầu cập nhật giá cổ phiếu của 1 công ty nào đó
- Stock Tên cổ phiếu cần hủy bỏ
- Obj Đối tượng trình khách yêu cầu hủy bỏ cổ phiếu
*/
Public Void Canel ( String stock , StockNotify Obj) throw s RemoteException;
/**
- Trả về danh sách các cổ phiếu đã đăng ký được cập nhật giá
- Obj Đối tượng trình khách yêu cầu cập nhật giá
*/
Public Stock[ ] list (StockNotify Obj ) throws RemoteException ;
/**
- Hủy bỏ tất cả yêu cầu cập nhật giá
- Obj Đối tượng trình khách yêu cầu hủy bỏ quá trình cập nhật
*/
Public void canel All (StockNotify obj) throws RemoteException ;
}
Bước 4 : Cài đặt chi tiết cho đối tượng chủ .Để rút gọn chúng ta cài đặt giao tiếp StockWatch chung với trình thiết lập và đăng ký đối tượng gọi tên StockServer
Ví dụ : StockServer,java
Import java.rmi.*;
Import java.rmi.server.*;
Import java .rmi.Registry.LocatRegistry;
Import java .util.*;
Public Class StockServer implement StockWatch , Runnable
{
/** Tạo bảng lưu giữ các đối tượng StockNotify của máy khách */
Private Hashtable notifyTable = new Hashtable ();
/** Tạo bảng lưu trữ cổ phiếu của các công ty */
Private Hashtable stockTable = new Hashtable ();
/** Tuyến chịu trách nhiệm cập nhật giá trị cổ phiếu sau một thời gian chỉ định */
Private Thread notifyer = null
/* Danh sách các công ty bán cổ phiếu */
Private static String [] = {“Sun”,”HP”, “Microsoft”, “Compaq” , “Novell”,”IBM”,”Apple”,”AOL”,”Inprise”,”SGI”};
/**
- Phương thức khởi dựng của StockServer
*/
Public StockServer () throws RemoteException
{
For (int i = 0; i < name.length;i++) {
// Tạo danh sách các cổ phiếu tương ứng với danh sách các công ty
Stocktable.put(Name[i] , new Stock(Name [i])) ;
}
}
/**
- Trả về đối tượng cổ phiếu Stock cho máy khách với giá trị cập nhật mới nhất
- Stock Tên cổ phiếu
- Obj Đối tượng trình khách yêu cầu cập nhật giá
*/
Public Stock Watch(String stock , StockNotify obj) throws RemoteException
{
System .out.println (“StockServer.watch:”+stock)
// Lấy về danh sách các cổ phiếu
Vector stock (Vector) notifyTable.get(obj);
// Nếu chưa có thì tạo danh sách cổ phiếu mới
If (stocks == null) {
Stocks = newVector();
notifyTable.put(obj , stocks );
}
// Nếu chưa có cổ phiếu mà trình khách yêu cầu thì thêm cổ phiếu mới vào
danh sách .
if (! Stocks .contains(stock)) {
Stocks .addElement (stock);
}
// Khởi động tuyến theo dõi và cập nhật giá cổ phiếu
If (notifier == null) {
Notifier = new thread (this , “StockNotifier”) ;
Notifier.start ();
}
Return(Stock) stockTable.get(stock);
}
/**
- Hủy bỏ yêu cầu cập nhật giá cổ phiếu
- Stock Tên cổ phiếu
- Obj Đối tượng trình khách yêu cầu cập nhật giá
*/
Public void cancel (String stock , stockNotify )
{
Vector stocks = (Vector) notifyTable.get(obj);
Stock[ ] stockList = null;
If (stocks ! = null){
Enumeration enum = stocks.elements();
stockList = new stocks [ stocks.size()];
int i = 0 ;
// Trích ra danh sách các cổ phiếu từ bảng cổ phiếu
While (enum.hasMoreElements()) {
String stockname = (String) enum.nextElement();
StockList[ i++] = (stock)stockTable.get(stockname);
}
}
// Trả về danh sách cổ phiếu
Return stockList;
}
/**
* Hủy bỏ việc cập nhật của tất cả các cổ phiếu
*/
Public synchronized void cancelAll (s tockNotify obj)
{
notifyTable.remote(obj);
}
/**
* Sinh giá ngẫu nhiên cho từng cổ phiếu
*/
Private void generateUpdate()
{
Enumeration enum = stockTable.elements();
While (enum.hasMoreElements()) {
Stock stock = (stock)enum.nextElement();
}
}
/**
* Tạo tuyến định kỳ cập nhật giá cổ phiếu cho những công ty được phía máy khách yêu cầu
*/
Public void run ()
{
Boolean done = false;
Do {
Try {
// Cập nhật dữ liệu 2s 1 lần
Thread.currentThread().Sleep(2000);
} catch (interruptException e) {
}
// Ghi nhận ngày giờ giá cổ phiếu thay đổi
Date date = new Date();
// Tạo giá mới cho cổ phiếu
GenerateUpdate();
// Yêu cầu khách nhận dữ liệu đã cập nhập
Enumeration enum = notifyTable.keys();
While (enum.hasMoreElements()) {
StockNotify obj = (StockNotify)enum.nextElement();
Stock [ ] stockList = List (obj);
If (stockList ! = null) {
// Gửi số liệu đã cập nhật
Try {
System.out.println (“StockServer.run: sending update”+date);
Obj.update(date, stockList);
} catch (RemoteException e ) {
e.printStackTrace ();
cancelAll (obj);
}
}
}
// Kiểm tra xem còn giá cổ phiếu trong danh sách cần cập nhật hay không
If (notifyTable.isEmpty()) {
Notifier = null;
Done = true;
}
} While (! done);
}
/**
* Chương trình chính : kiến tạo đối tượng chủ; tự tạo bộ đăng kí registry. Đăng kí và răng buộc đối tượng chủ với registry
*/
public static void main (string args [ ])
{
// Cài đặt lớp bảo vệ cho máy chủ
System.setSecurityMana ger(new RMISecurityManager());
Try {
// Tự tạo bộ đăng kí registry hoạt động trên cổng 1234
System.out.println(“StockServer.main : creating server”);
LocateRegistry.createRegistry(1234);
// Tạo đối tượng chủ
System.out.println(“StockServer.main : creating server”);
StockServer server = new StockServer ();
// Thông báo khả năng gọi được từ xa của đối tượng chủ với máy ảo Java
UnicastRemoteObject.exportObject (server);
// Rằng buộc đối tượng chủ với registry ở cổng 1234
System.out.println(“StockServer.main : binding server”);
Naming.rebind(“// localhost : 1234 / StockServer”, server);
System.out.println (“StockServer.main : done”);
}
Catch (Exception e ) {
System.out.println(“StockServer.main:an exception occurred : “ +e.getMessage());
e.printStrackTrace();
}
}
}
Ngoài việc cài đặt giao tiếp StockWatch, StockServer cài đặt thêm giao tiếp runnable. Giao tiếp runnable được dùng với mục đích tạo ra tuyến (thread) chạy độc lập định kỳ 2s 1 lần tính toán giá cổ phiếu và yêu cầu đối tượng StockNotify ở trình khách cập nhật lại thông tin.
Quá trình cài đặt đối tượng ở máy chủ đã hoàn tất. Chúng ta sẽ thiết kế 1 Applet ở máy khách (hay trình khách ) có khả năng triệu gọi phương thức của StcokSever trên máy chủ
Bước 5 : Xây dựng Applet và cài đặt đối tượng StockNotify
Ví dụ: StockApplet.java
Import java .applet.Applet;
Import java.awt.*;
Import java.net.URL;
Import java.rmi.* ;
Import java.rmi.server.* ;
Import java.util.* ;
/**
* Bạn lưu ý stockApplet của ta vừa là Applet vừa là StockNotify. Vì StockNotify được tham chiếu bởi đối tượng StockSever nên ta cần gọi lệnh UnicastRemoteObject.exportObject() để thông báo với mấy ảo Java sự hiện diện của StockNotify
*/
Public Class StockApplet extends Applet implements StockNotify{
/** Tổng số cổ phiếu tối đa cần hiển thị */
Static final int MAX _UPDATES = 34 ;
/** Chiều rộng của bảng vẽ biểu đồ báo giá */
Private static final int awidth = 500;
/**Chiều cao của bảng vẽ biểu đồ báo giá * /
Private static final int height = 350;
/** Mảng chứa các thời điểm cập nhật */
Private Vector time = null;
/** Mảng chứa các hộp checkbox đánh dấu giá cổ phiếu có cần cập nhật hay không*/
Private Vector checkboxes = null ;
/** Bảng ánh xạ tên cổ phiếu với đối tượng Stock*/
Private Hashtable stockTable = null;
/** Tham chiếu đến đối tượng chủ */
Private StockWatch stockWatch = null;
/* Danh sách các công ty bán cổ phiếu cần liêm yết*/
Private static String name [ ] = {“Sun”,”HP”, “Microsoft”, “Compaq” , “Novell”,”IBM”,”Apple”,”AOL”,”Inprise”,”SGI”};
/* Màu sắc để vẽ biểu đồ */
Private Color color [ ] = { new Color(205,92,92) ,
Color, orange,
New Color (220,220,90),
New Color (85,107,47),
` Color.blue,
New Color (160,32,240),
New Color (238,130,238),
Color.black,
New Color (205,120,92),
New Color (0,100,0);
/**
* Cài đặt phương thức của đối tượng StockNotify
*/
Public void update(Date date , Stock [ ]stock)
{
System.out.println(“StockApplet.update” +date);
// Lưu lại ngày giờ cập nhật
If (time.size()== MAX_UPDATES){
Time.remoteElementAt(0);
}
Time.addElement(date);
// Lưu lại dữ liệu giá cổ phiếu . Bạn cần xem phần cài đặt của lớp StockData bên dưới
Int numUpdates = time.size();
For (int i = 0; i <stock.length;i++) {
StockData data = (StockData)stockTable.get(stock [ i].symbol);
If (data! = null) {
Data.update (stock [i],numUpdates);
}
}
// Vẽ lại bảng báo giá cổ phiếu
Repaint();
}
/**
* Khởi tạo Applet
*/
Public void init ()
{
// Khởi tạo các biến ban đầu
Time = new Vector (MAX_UPDATES) ;
StockTable = new Hashtable();
StockWatch = null;
// Thông báo sự hiện diện của đối tượng StockNotify
System.out.println (“StockApplet.init: exporting remote object”);
UnicastRemoteObject .exporObject( this );
// Tìm đối tượng trên máy chủ
URL base = getDocumentBase () ;
String serverName = ‘’rmi // localhost :1234/StockServer’’ ;
System.out.println (“StockApplet init”);
StockWatch = (StockWatch) Naming.lookup(serverName);
// Đăng kí các cổ phiếu mà Applet muốn trình chủ cập nhật giá
For (int i = 0; i<name.length;i++) {
System.out.println (“StockApplet.init: watch stock”+name [ i]);
StockWatch.watch(name [ i] this);
stockTable.put(name [ i],new StockData(name [i],color[i]));
}
System.out.println (“StockApplet.init: done registering stocks”);
} catch (Exception e){
Add(new Label(“exception occurrent during initialization.Check the log”));
Add(new Lablel (e.getClass().getName() + “:” +e.getMessage()));
System.out.println (“got exception:” +e.getMessage());
e.printStackTrace();
return;
}
}
// Vẽ các ô checkbox hiển thị tên cổ phiếu của các công ty
Checkboxes = new Vector();
Enumeration enum = stockTable.elements();
Int i = 0;
While (enum.hasMoreElements()) {
StockData data = (StockData) enum.nextElement ();
SensitiveCheckbox cb = new SensitiveCheckbox(data,this);
Data.cb = cb;
Checkboxes .add(cb);
Add(cb);
Cb.setState(data.displayed) ;
Cb.reshape(10,i++*25+35,110,18);
}
}
/**
* Yêu cầu đối tượng chủ ngừng cung cấp thông tin khi Applet chấm dứt hoạt động
*/
Public void destroy()
{
// Yêu cầu đối tượng chủ hủy bỏ cập nhật thông tin
If (stockWatch ! = null) {
Try {
stockWatch.cancelAll (this);
}catch(Exception e) {
}
}
}
/**
* Cập nhật và vẽ đồ thị của giá cổ phiếu
*/
Public void paint (Graphics g ) {
G.setColor(Color.black);
g.drawRect(0,0,awidth-1.height-1);
float miny = 0,0f;
float maxy = 75,0f;
// Vẽ đồ thị của tất cả dữ liệu
Enumeration enum = stockTable.elements();
While (enum.hasMoreElements()) {
StockData data = (StockData )enum.nextElement();
Int size;
Stock [ ] updates;
Synchronized(data.updates) {
Size = data.updates.size();
Updates = new Stock [ size];
Data.updates.copyInto(updates);
}
g.setColor(data.color);
if ( data.displayed) {
// Vẽ hình chữ nhật bao quanh cổ phiếu nếu chuột di chuyển đến cổ phiếu đó
If (data.cb! = null && data.cb.haveMouse()) {
Point p = data.cb.location();
Dimersion d = data.cb.size();
g.drawRect(p.x-1,p.y-1,d.awidth+4,d.height+4);
g.drawRect(p.x-2,p.y-2,d.awidth+4,d.height+4);
// Vẽ đồ thị
If (size > 0 )
g.drawLine(p.x+d.awidth+2,p.i+10,150,scale(updates [ 0].current));
}
Int x = 150,inc = 10;
For (int i = 0; i< size; i++) {
If (updates [ i] i= null) {
g.drawRect(x-1,scale(updates [ i].current)-1,3,3);
if ((i <size-1) &&updates [ i+1] !=null) {
int x2 = x + inc;
g.drawLine(x,scale(updates [i].current)),x2,scale (updates [i+1].current));
}
}
X + =inc;
}
}
}
}
/**
* Đối tọa độ tương đối y
*/
Int scale(float y) {
Return height – (int)(y*5+.5);
}
Void setMouseHere (boolean display)
{
Enumeration enum = stockTable.elements();
While (enum.hasMoreElements ()) {
StockData data = (StockData)enum.nextElements ();
Data,cb.mouseHere = display;
}
}
/**
* Lớp StockData chứa cập nhật của giá cổ phiếu vè hiển thị thông tin về cổ phiếu
*/
Static Class StockData {
Public String name;
Public Vector updates;
Public Color color;
Public boolean displayed;
Public SensitiveCheckbox cb;
Public StockData (String name,Color cl) {
This.name = name;
This.color = cl;
This.updates = new Vector (StockApplet.MAX_UPDATES) ;
Displayed = true;
}
/**
*Cập nhật
*/
Void Update(Stock stock , int numUpdates) {
Synchronized (updates) {
If (updates.size()) == StockApplet.MAX_UPDATES) {
Updates .remoteElementAt(0);
}
If (updates.size() <numUpdates) {
For (int i= updates.size();i<numUpdates-1;i++) {
Updates.addElement(stock);
}
}
Updates.addElement(stock);
}
}
}
/**
* Lớp SensitiveCheckbox dùng để xác định chuột di chuyển
*/
Static Class SensitiveCheckbox extends canvas {
StockData data;
Boolean state = true;
StockApplet panel;
Boolean MouseHere = false;
Public boolean haveMouse() {
Return MouseHere;
}
Public SensitiveCheckbox (StockData data,StockApplet p) {
This.data=date;
Panel = p;
}
Public boolean mouseEnter (Event evt,int x , int y) {
If (State) {
Panel.setMouseHere(false);
MouseHere = true;
Panel.repaint();
}
Return false ;
}
Public boolean MouseExit(Event evt,int x,int y) {
If (State) {
MouseHere = false;
Panel.repaint();
}
Return false;
}
Public boolean MouseDown (Event evt, int x,int y){
If (State)
State = false;
Else
State = true;
MouseHere = state;
Data.displayed = state;
Repaint();
Panel.repaint();
Return true;
}
Public void paint(Graphic g) {
g.setColor(Color.black);
g.drawLine (4,4,14,4);
g.drawLine (4,4,4,14);
g.setColor(Color.gray);
g.drawLine (5,14,14,14);
g.drawLine (14,5,14,14);
g.setColor(Color.color);
g.fillRect(5,5,8,8);
g.setColor (Color .color);
g.drawString(data.name,17,15);
g.setColor(Color.black);
if ( state ) {
if (data .color == Color. black)
g.setColor(Color.gray);
if (data .color==color.blue)
g.setcolor(Color.gray);
g.drawLine (5,5,13,13);
g.drawLine (5,6,12,13);
g.drawLine (13,5,5,13);
g.drawLine (13,6,6,13) ;
}
}
Public void setState(Boolean s){
State = s;
Repaint();
}
}
}
StockApplet của ta cần được đặt trong 1 trang web . Ban tao trang web StockApp.html có nội dung như sau :
Ví dụ 2-53:StockApp.html
<HTML>
Stock Exchange from java
< Applet codebase = “.”
Code= “StockApplet”
Width = 500 Height = 350>
</ Applet>
</HTML>
Trước khi biên dịch chúng ta cần tạo tập tin policy quy định cơ chế bảo mật của Applet và trình chủ như sau:
Mở trình soạn thảo notepad trong windows nhập vào chết độ bảo mật và lưu tập tin xuống đĩa với tên Security.Policy.
Ví dụ 2-54 :Tập tin chính sách Security.Policy
Grant {
Permission java. Security.Allpermission;
} ;
Bước 6: Cuối cùng là biên dich và chay chương trình ở cả 2 phía khách chủ. Bạn hãy lưu tất cả mã nguồn và tập tin Security.Policy, StockApp.html vào thư mục
C: RMI Stock . Chuyển vào thư mục này chuyển vào thư mục này thực hiện các bước biên dich như sau :
Biên dich mã nguồn :
C: RMI Stock> Javac * Java
Biên dich tập tin trung gian cho đối tương StockServer:
C: RMI Stock > rmic StockServer
Biên dịch tập tin trung gian cho đối tương StockNotify:
C: RMI Stock > rmic StockApplet
(Bạn lưu ý , StockApplet của ta do cài đặt giao tiếp StockNotify nên bản thân nó là 1 đối tượng có thể phục vụ cho giao tiết StockNotify thật sự)
Tạo và đăng ký đối tượng tren máy chủ
C: RMI Stock > java Djava.Security.Policy= Security.Policy Stock Server
(Chúng ta kô cần khởi động chương trình rmiregistry , Stockserver tự tạo bộ đăng ký Registry ở cổng 1234 với registry chính bản thân nó.)
Khởi động Applet trên máy khách :
C: RMI Stock > AppletViewr StockApp.html
Kết quả chương trình sẽ được hiển thị như hình 2-11.Applet liệt kê 1 bảng giá cổ phiếu cùng với đồ thị biểu diễn biến động của giá cổ phiều đang tăng hay giảm trông rất sinh đọng > Bạn có thể di chuyển chuột dến từng loại cổ phiếu của các công ty khác nhau. Kích chuột vào ô Checkbox , khi bạn không đánh đau ô Checkbox , đối tượng StockNotify sẽ không còn yêu cầu máy chủ cập nhật giá cổ phiếu của công ty đó nữa .
Điểm thú vị là Applet của ta có khả năng chạy trên browser . Không cần bất kỳ cài đặt nào từ phía máy khách .Những công việc cần làm của trình khách chỉ là mở trình duyệt (IE hay NetScape) và đánh vào địa chỉ URL dẫn đến trang web StockApp . html do nhà cung cấp chỉ định . Việc cài đặt StockSever , StockNotify là do trình chủ đảm nhiệm.