Cấu trúc một MIDlet có thể thực hiện một thiết lập trước chỉ một lần trong vòng đời MIDlet. Cấu trúc tiêu biểu của một MIDlet như sau:
ã Các màn hình của MIDlet và các lệnh trừu tượng. Các màn hình có thể không xuất hiện, như các cảnh báo, không được tạo đặc thù MIDlet cụ thể mà thay vào đó, chúng được tạo chỉ khi chúng được coi là cần thiết.
ã Kết hợp với các màn hình là các lệnh trừu tượng. Tất cả màn hình nên có ít nhất một lệnh trừu tượng. Một câu lệnh trừu tượng đơn có thể hỗ trợ cho nhiều màn hình.
ã Gán một phương thức lắng nghe sự kiện cho mỗi màn hình. Phương thức lắng nghe sự kiện là lớp được thực thi từ giao diện CommandListener.
ã Thiết lập các trường tĩnh hay khởi tạo. Một lớp MIDlet điển hình có các trường để kiểm soát màn hình và các câu lệnh trừu tượng.
Người xây dựng MIDlet cũng có thể thiết lập việc hiển thị ban đầu của MIDlet. Tác vụ này cũng có thể được thực hiện trong phương thức startApp (xem Tạo các phương thức vòng đời để biết thêm thông tin).
48 trang |
Chia sẻ: Dung Lona | Lượt xem: 920 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Xây dựng chương trình tra cứu tỷ giá hối đoái qua mobile, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
không sử dụng tài nguyên chia sẻ, các phương thức trống.
Ví dụ 5: Các phương thức vòng đời của HelloMIDlet
/**
* Khởi động MIDlet; phương thức này không làm gì cả bởi vì
* MIDlet không đòi hỏi tài nguyên chia sẻ.
*/
public void startApp() {
}
/**
* Tạm ngưng MIDlet; phương thức này không làm gì cả bởi vì
* không có các hoạt động nền hay tài nguyên chia sẻ
* được đóng..
*/
public void pauseApp() {
}
/**
* Giải phóng MIDlet; phương thức này không làm gì cả bởi vì
* không có thứ gì để dọn dẹp – tức là không được kiểm soát bởi
* bộ thu gom rác.
*
* @Tham số unconditional – MIDlet phải được giải phóng.
* Nếu là true, MIDlet phải dọn dẹp và giải phóng tất cả tài nguyên.
* Nếu là false, MIDlet có thể ném ra ngoại lệ MIDletStateChangeException để
* chỉ định là MIDlet sẽ không được giải phóng vào thời điểm này.
*/
public void destroyApp(boolean unconditional) {
}
Thư viện API (Application Programming Interface) và chế độ bảo mật
Chế độ bảo mật MIDP 2.0 sẽ bảo vệ thư viện các gói trong thư viện API. Các gói API trong bảng dưới đây là bảo mật thật trọng. Nếu sử dụng chúng trong MIDlet của mình, bạn phải có kiến thức khi đóng gói nó vào trong bộ MIDlet.
Bảng 2: Các API dùng để phân quyền
API
Mô tả
javax.microedition.io.HttpConnection
API dành cho việc tạo các yêu cầu HTTP
javax.microedition.io.HttpsConnection
API dành cho việc tạo các yêu cầu HTTP bảo mật (https://)
javax.microedition.io.Connector
API dành cho việc tạo các kết nối cho các giao thức
HTTP
HTTPS
Datagram
Datagramreceiver
Socket
Serversocket
SSL
Comm
javax.microedition.io.PushRegistry
API dành cho việc thiết lập MIDlet để sử dụng chức năng push (đó là, thiết lập MIDlet để thiết bị chạy và kiểm soát được thông điệp đến
Không phải tất cả các API đều được bảo mật. Bảng dưới đây chỉ ra các API được sử dụng rộng rãi:
Bảng 3: Các API không đòi hỏi cấp phép
API
Mô tả
javax.microedition.rms
API dành cho việc sử dụng vật lưu dữ liệu lâu dài trên thiết bị
javax.microedition.midlet
Lớp MIDlet và các API vòng đời MIDlet
javax.microedition.lcdui
API giao diện người sử dụng
javax.microedition.lcdui.game
API dành cho các MIDlet là các trò chơi (game)
javax.microedition.media và javax.microedition.media.controls
API dành cho việc chơi các file âm thanh trên thiết bị
Phần III
Biên dịch và kiểm tra trước một MIDlet
Giống như tất cả các ứng dụng được viết bằng ngôn ngữ lập trình JavaTM, bạn phải biên dịch một MIDlet trước khi chạy nó. Ngoài ra bạn còn phải kiểm tra trước MIDlet đó. Mỗi bước kiểm tra trước sẽ thêm thông tin vào các tệp .class để chúng có thể chạy trong môi trường MIDlet (các tệp .class này vẫn có thể chạy bằng Java 2 Platform, Standard Edition).
Khi chạy MIDlet, bạn sẽ sử dụng các tệp .class đã được kiểm tra. Do đó, khi biên dịch MIDlet, bạn đặt các tệp đã được biên dịch vào trong một thư mục tạm để kiểm tra trước. Đặt đầu xuất cho việc kiểm tra trong một vị trí cố định hơn, từ đó bạn có thể đóng gói hay thực thi MIDlet. Hình sau đây sẽ giải thích cho quá trình này:
Hình 7: Quá trình xây dựng một MIDlet
Biên dịch tệp nguồn MIDlet
Để biên dịch một MIDlet ta sử dụng trình biên dịch thường lệ javac. Sử dụng tùy chọn –d để javac tất cả các tệp .class là đặt vào trong một thư mục đơn tạm. Điều này tạo cho những bước tiếp theo của quá trình xây dựng MIDlet được dễ dàng hơn.
Ví dụ, để tạo một thư mục đầu xuất C:\MyMIDlet\tmpclasses, và biên dịch MIDlet trong thư mục đó, bạn nhập lệnh tiếp theo:
C:\cd MyMIDlet
C:\MyMIDlet> mkdir tmpclasses
C:\MyMIDlet> javac –classpath classes -d tmpclasses src/example/HelloMIDlet.java
Có một tùy chọn cho javac mà bạn sử dụng nếu MIDlet của bạn đang dùng chức năng push được định nghĩa trong Đặc tả MIDP 2.0, tùy chọn này là -bootclasspath. (Chức năng push cho phép MIDP thực thi một MIDlet để quản lý một thông điệp được gửi đến nó. Ví dụ, nếu bạn đang viết một MIDlet để một người sử dụng có thể nhận các báo cáo về giao thông, bạn có thể có MIDlet sử dụng chức năng push để nhận những cảnh báo đề phòng cho tuyến đường của người sử dụng).
Tùy chọn –bootclasspath phải chỉ định vị trí của các tệp MIDP class (MyMIDlet/classes) bởi vì trận tự của các lớp trong J2SE và J2ME là khác nhau. Ví dụ, lớp FilterInputStream của J2SE không phải là phần trong J2ME. Nếu MIDlet được biên dịch với các lớp J2SE, nó sẽ kiểm tra lỗi trước (bước tiếp theo trong quá trình xây dựng MIDlet). Với lựa chọn –bootclasspath, javac sử dụng các tệp class trong J2ME.
Ví dụ tiếp theo sẽ chỉ ra câu lệnh javac và tùy chọn –bootclasspath được sử dụng để biên dịch MIDlet PushExample:
C:\MyMIDlet> javac –bootclasspath c:/MyMIDlet/classes –classpath
C:/MyMIDlet/classes PushExample.java
Chú ý: Câu lệnh sử dụng cả hai tùy chọn – bootclasspath và -classpath. Tùy chọn –classpath cung cấp nơi lưu giữ lệnh javac để tìm kiếm các lớp không có trong J2SE, như các lớp trong gói javax.microedition. Điều này không ảnh hưởng đối với nền tảng được sử dụng (J2SE hoặc J2ME). Tùy chọn –bootclasspath chỉ định vị trí của các tệp nền tảng Java.
Kiểm tra các tệp đã biên dịch
Trình kiểm tra trước tạo ra các tệp .class mới chứa thông tin thêm vào trong thực thi tham chiếu bắt buộc. Nếu một lớp không được kiểm tra trước, MIDP sẽ không cho phép sử dụng nó (các lớp đã được kiểm tra trước vẫn có thể được sử dụng với một JRE (Java 2 Runtime Environment). Trình kiểm tra trước cũng có thể kiểm tra các tệp class để chắc chắn là chúng không sử dụng các đặc điểm của ngôn ngữ lập trình Java mà bị chặn bởi đặc tả CLDC (để biết thêm thông tin về đặc tả CLCD, bạn vào:
Trình kiểm tra trước nằm trong thư mục \bin; chứa tệp thực thi preverify. Sử dụng lệnh không có các tùy chọn trợ giúp. Ví dụ, bạn có thể nhận trợ giúp với câu lệnh:
C:\MyMIDlet\bin> preverify
2.1 Kiểm tra trước các tệp class
Cách đơn giản nhất để chạy trình kiểm tra trước là phải tạo các tệp .class mà không cần kiểm tra các đặc điểm ngăn cấm.
Với cách này, có thể bạn muốn sử dụng trình kiểm tra trước nếu bạn biên dịch lại sau khi đã ấn định được những lỗi đơn giản.
Theo các này, để chạy trình kiểm tra trước, bạn phải cung cấp các lớp và các tệp đầu vào để được kiểm tra. Các tệp đầu vào có thể là thư mục chứa các tệp .class, hoặc JAR, hay ZIP. Nếu bạn cung cấp một thư mục, trình kiểm tra trước cũng kiểm tra các thư mục con của nó. Ví dụ sau đây sẽ chỉ ra câu lệnh preverify được sử dụng để kiểm tra .class trong thư mục tmpclasses và trong các thư mục con của nó:
C:\MyMIDlet> bin\preverify -classpath classes; tmpclasses tmpclasses
Theo mặc định, trình kiểm tra trước sẽ ghi các tệp class mới vào thư mục ./output. Bạn có thể thay đổi thư mục này như trong ví dụ sau bằng cách kiểm tra trước một tệp class và đưa nó vào thư mục classes:
C:\MyMIDlet> bin\preverify -classpath classes; tmpclasses -d classes HelloMIDlet
Sau khi bạn chạy trình kiểm tra trước, những nội dung của thư mục đầu ra sẽ tương ứng với kiểutất cả các tệp của các tệp đầu vào mà bạn cung cấp. Thư mục này sẽ chứa một tệp .class, một cây thư mục tương ứng với mỗi thư mục đầu vào, và một tệp JAR tương ứng với mỗi tệp JAR đầu vào.
Kiểm tra trước và sát hạch lại các tệp class
Trong ngôn ngữ lập trình Java, để sử dụng cả 2 đặc điểm này không nằm trong đặc tả CLDC, bạn cần phải sử dụng một hoặc nhiều hơn các tham số cho câu lệnh preverify. Các tham số kèm theo có thể kiểm tra tính hiện hữu của các điểm hoạt động động, sử dụng trình hoàn thiện và triệu gọi phương thức nguyên thủy từ các lớp ứng dụng. Ví dụ sau kiểm tra các vấn đề được đề cập ở trên:
C:\MyMIDlet> bin\preverify -nofp -nofinalize -nonative -classpath classes; tmpclasses -d classes HelloMIDlet
Ví dụ tiếp theo là một phiên bản đơn giản hơn phiên bản trước đó. Nó sử dụng một chuyển đổi đơn tương đương với cách sử dụng cùng lúc các tham số -nofp, -nofinalize, và nonative:
C:\MyMIDlet> bin\preverify -cldc -classpath classes; tmpclasses -d classes HelloMIDlet
Phần IV
Đóng gói MIDlet
Để người sử dụng có thể tải về và chạy một MIDlet bạn phải tiến hành đóng gói MIDlet đó vào trong một bộ MIDlet. Một bộ MIDlet gồm 2 tệp: tệp JAR – dùng để quản lý các lớp MIDlet và tài nguyên (như đồ họa), và tệp JAD (JavaTM Application Description) – dùng để quản lý các giá trị và thuộc tính mô tả cho bộ MIDlet và các MIDlet nằm trong nó.
Các mục sau đây sẽ mô tả một MIDlet được đóng gói vào bộ MIDlet như thế nào:
Tạo tệp JAR
Tệp JAR là một gói gồm nhiều tệp được kiểm tra trước cho MIDlet và các tệp hỗ trợ, như đồ họa. Bạn tạo tệp JAR bằng câu lệnh jar (câu lệnh này được phân phối trong J2SE).
Một tệp JAR được dùng để phân phối một bộ MIDlet phải có:
Một tệp hiển minh (text).
Các tệp class của các MIDlet trong bộ.
Các tệp tài nguyên (như đồ họa) dành cho các MIDlet trong bộ.
Các bước để tạo một tệp JAR:
Bước 1: Phải bảo đảm rằng tất cả các tệp class (đã được kiểm tra trước) của bộ MIDlet nằm trong thư mục yêu cầu của nó.
Ví dụ:
c:\MyMIDlet> dir classes
Volume in drive C has no label.
...
05/21/2008 03:32p 1,555 HelloMIDlet.class
...
Bước 2: Chép các tệp tài nguyên dành cho các MIDlet vào thư mục chứa các tệp đã được kiểm tra trước.
Giả dụ như MIDlet không có các tệp tài nguyên, nó sẽ yêu cầu một tệp đồ họa mySplashImage.pnp. Câu lệnh sau sẽ chép tệp đồ họa này vào trong thư mục classes:
c:\MyMIDlet> cp src/example/mySplashImage.png classes/
Bước 3: Đặt tên cho tệp JAR
Trong bước này bạn phải chỉ định cho tệp jar một cái tên. Ví dụ bạn đặt tên cho MIDlet đầu tay của bạn là HelloMIDlet.jar
Bước 4: Chuyển đến vị trí của thư mục có các tệp class đã được kiểm tra và các tệp tài nguyên.
Ví dụ:
c:\MyMIDlet> cd classes
Bước 5: Tạo một tệp hiển minh
Tệp hiển minh là một tệp văn bản có phần mở rộng là .mf (đơn giản là tạo bằng Notepad). Trong tệp này ít nhất phải có các thuộc tính sau:
MIDlet–Name – Tên sẽ được biểu thị cho người sử dụng
MIDlet–Version – Số hiệu phiên bản của MIDlet trong đặc tả major.minor.micro (được mô tả trong Đặc tả phiên bản Sản phẩm Java:
MIDlet–Vendor : Tác giả của MIDlet.
Nếu sử dụng các gói API bảo mật nhạy cảm, bạn có thể khai báo chúng trong tệp hiển minh này (nếu không nằm trong tệp này, chúng phải nằm trong tệp JAD). Để khai báo chúng, sử dụng các thuộc tính sau:
MIDlet–Permissions – Các đặc quyền quyết định cho chức năng hợp lệ của bộ MIDlet
MIDlet–Permissions – Opt – cung cấp các tùy chọn đặc quyền mà MIDlet mong muốn (giả dụ sử dụng thuộc tính này nếu bộ MIDlet thực thi với các chức năng giảm thiểu).
Giữa MIDle–Permissions và MIDlet–Permissions – Opt là các dấu phẩy ngăn cách, khoảng trắng (Unicode U+0020) và các tab (Unicode U+0009) sẽ được bỏ qua. Bảng sau đây sẽ chỉ ra sự tương ứng giữa chức năng của MIDP và các đặc quyền:
Bảng 4: API và các Đặc quyền tương đương
API
đặc quyền tương đương
javax.microedition.io.HttpConnection
javax.microedition.io.Connector.http
javax.microedition.io.HttpsConnection
javax.microedition.io.Connector.https
javax.microedition.io.Connector
Sử dụng các đặc quyền tương đương với giao thức bạn sử dụng khi tạo một kết nối:
javax.microedition.io.Connector.http
javax.microedition.io.Connector.https
javax.microedition.io.Connector.datagram
javax.microedition.io.
Connector.datagramreceiver
javax.microedition.io.Connector.socket
javax.microedition.io.Connector.serversocket
javax.microedition.io.Connector.ssl
javax.microedition.io.Connector.comm
javax.microedition.io.PushRegistry
javax.microedition.io.PushRegistry
Tệp hiển minh cũng có thể chứa các thuộc tính sau (các thuộc tính không nằm trong tệp này phải nằm trong tệp JAD):
MIDlet–n – các dấu phẩy ngăn cách giữa tên của MIDlet, biểu tượng, và lớp. Trong đó: tham số n chỉ ra phần tử MIDlet thứ n trong tệp JAR. Giá trị nhỏ nhất của n là 1 và n tăng lên 1 đơn vị cho mỗi MIDlet tiếp theo; đồng thời cũng cung cấp một biểu tượng để để lựa chọn.
MicroEdition–Profile – Các đặc tả nền tảng J2ME mà MIDlet yêu cầu. Ngăn cách giữa các đặc tả là một khoảng trắng (Unicode x20). Theo MIDP 2.0, trị số này có trong đặc tả MIDP 2.0.
MicroEdition–Configuration – cấu hình nền tảng J2ME mà MIDlet yêu cầu. Giữa các cấu hình là một khoảng trắng (Unicode x20). Theo MIDP 2.0, trị số này có trong đặc tả CLDC-1.0.
Tệp hiển minh cũng cho phép lưu trữ các thuộc tính khác. Để biết thêm thông tin về các thuộc tính hợp lệ trong một tệp JAR của một MIDlet, xem đặc tả MIDP 2.0 [JSR-000118] tại địa chỉ:
Ví dụ, tệp hiển minh dành cho tệp HelloMIDlet.jar, gọi là HelloMIDlet.mf trông như sau:
MIDlet-Name: HelloWorld
MIDlet-Version: 2.0
MIDlet-Vendor: Sun Microsystems, Inc.
Bước 6: Tạo tệp JAR với công cụ jar
Đưa tệp hiển minh, các tệp .class và các tệp tài nguyên vào trong tệp JAR (xem tài liệu nền tảng Java của bạn để biết thêm thông tin về câu lệnh jar).
Ví dụ:
c:\MyMIDlet\classes> jar -cmf HelloMIDlet.mf HelloMIDlet.jar HelloMIDlet.class
Tạo tệp JAD
Một tệp JAD là một tệp văn bản mà bạn có thể tạo bằng bất kỳ một trình soạn thảo nào (giả sử dùng Notepad). Nó có cú pháp như sau:
attribute: value
Tệp JAD phải có ít nhất các thuộc tính sau:
MIDlet–Name – Tương tự thuộc tính trong tệp JAR. Xem lại bước 5 của mục trên.
MIDlet–Version – Tương tự thuộc tính trong tệp JAR. Xem lại bước 5 của mục trên.
MIDlet–Vendor – Tương tự thuộc tính trong tệp JAR. Xem lại bước 5 của mục trên.
MIDlet–Jar–URL – Vị trí của tệp JAR.
MIDlet–Jar–Size – Kích thước của tệp JAR (byte).
Tệp JAD cũng có thể chứa các thuộc tính khác, bao gồm các thuộc tính có ở bước 5 của mục trước. Để biết thêm thông tin về các thuộc tính hợp lệ trong tệp JAD của một MIDlet, xem đặc tả MIDP 2.0 [JSR-000118] tại địa chỉ:
Tệp JAR và JAD phải có các trị số cho các thuộc tính MIDlet–Name, MIDlet–Version, và MIDlet–Vendor. Nếu các trị số không giống nhau thì MIDP không cho phép tải MIDlet.
Nếu các thuộc tính khác của tệp JAR và tệp JAD giống nhau thì các thủ tục sẽ phụ thuộc vào độ tin cậy của bộ MIDlet:
Trusted – Những trị số của các thuộc tính giống nhau phải y hệt nhau hoặc Thực thi tham chiếu MIDP sẽ không cho phép tải MIDlet.
Not trusted – Những trị số của các thuộc tính giống nhau có thể khác nhau. Nếu chúng khác nhau, MIDP sẽ sử dụng các trị số có trong tệp JAD.
Ví dụ, tệp JAD của MIDlet Hello, HelloMIDlet.jar có thể trông như thế này:
MIDlet-Name: HelloWorld
MIDlet-Version: 2.0
MIDlet-Vendor: Sun Microsystems, Inc.
MIDlet-Jar-URL: HelloMIDlet.jar
MIDlet-Jar-Size: 1212
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.0
MIDlet-1: Hello World,, HelloMIDlet
Dấu hiệu xác nhận tệp JAR
Thiết lập độ tin cậy hết sức quan trọng đối với các bộ MIDlet, đó là việc sử dụng các gói thư viện API bảo mật nhạy cảm. Do đó các MIDlet tin cậy có thể truy xuất chức năng bảo vệ hơn là các MIDlet không tin cậy. Kiểm tra chữ ký của bộ MIDlet là cách mà một thiết bị có thể xác định được một bộ MIDlet có đáng tin hay không. Khi có một kết quả, dấu hiệu xác nhận một bộ MIDlet tạo ra chữ ký phù hợp để bộ MIDlet của bạn đáng tin hơn. (Xem thêm mục Sử dụng MIDP để biết thêm thông tin về chữ ký và xác nhận).
HelloMIDlet không truy xuất các gói API bảo vệ, bởi vì nó không cần để nhận dạng bộ MIDlet. Mục này cho ta thấy bộ MIDlet làm việc như thế nào.
Bộ MIDlet trong ví dụ dưới đây sẽ chỉ ra cặp khóa trong thuận toán mã hóa RSA được giải phóng. Cặp khóa nằm trong thư mục \bin\j2se_test_keystore.bin là một khóa có thể quản lý tiện ích keytool của nền tảng J2SE.(Xem tại: để biết thêm thông tin về tiện ích keytool). Mật khẩu cho tệp này là keystorepwd. Bí danh của cặp khóa là dummyca và mật khẩu chìa khóa riêng là keypwd. Tệp này được cung cấp cho các mục đích kiểm tra.
Khi phát hành các MIDlet, có thể bạn sẽ sử dụng một cặp khóa RSA kèm theo để xác nhận hoặc xác định độ dài trong một keystore J2SE với tiện ích keytool của nền tảng J2SE.
Để thực hiện việc này, ta làm theo các bước sau:
Bước 1: Thêm chứng chỉ cho cặp khóa công cộng vào tệp JAD bằng cách sử dụng tiện ích JadTool
Tiện ích JadTool sẽ thêm chứng nhận như trị số của thuộc tính có tên MIDlet–Certificate–m–n. Trong đó, m là số chuỗi xác thực (mặc định là 1; bạn có thể cung cấp một trị số khác với khóa chuyển đổi –chainnum), và n là một số nguyên dành cho các chứng thực mới, bắt đầu từ 1 và mỗi bước tăng lên 1 đơn vị khi bạn thêm các chứng thực mới vào tệp JAD.
Ví dụ, câu lệnh sau đây sẽ thêm chứng thực MIDlet–Certificate–1–1 vào tệp JAD:
c:\MyMIDlet\classes> java -jar ../bin/JadTool.jar -addcert -keystore ../bin/j2se_test_keystore.bin -alias dummyca -storepass keystorepwd -inputjad HelloMIDlet.jad -outputjad HelloMIDlet.jad
Bước 2: Kiểm tra chứng thực đã được thêm vào tệp JAD bằng cách sử dụng tiện ích JadTool
c:\MyMIDlet\classes> java -jar ../bin/JadTool.jar -showcert -certnum 1 -inputjad HelloMIDlet.jad
Subject: C=US, ST=CA, L=Santa Clara, O=dummy CA, OU=JCT, CN=thehost
Issuer : C=US, ST=CA, L=Santa Clara, O=dummy CA, OU=JCT, CN=thehost
Serial number: 3d3ece8a
Valid from Wed Jul 24 08:58:02 PDT 2002 to Sat Jul 21 08:58:02 PDT 2012
Certificate fingerprints:
MD5: 87:7f:5e:64:c8:dd:b4:bf:35:39:76:87:99:9b:68:82
SHA: 9d:c0:88:ce:08:83:cd:e6:fe:13:8b:26:f6:b4:df:e2:da:3c:25:98
Bước 3: Nếu bạn có một cặp khóa đi kèm một chuỗi xác thực, nhập khẩu các chứng thực trung gian
Nhập khẩu các chứng thực trung gian bằng cách sử dụng tiện ích JadTool với khóa chuyển đổi là -addcert (đã được đề cập ở bước 1), hãy thận trọng khi sử dụng sắp xếp chuỗi. Đó là, nếu công ty Acme cung cấp một chứng thực xác nhận cặp khóa của bạn, và công ty WidgetCertificates xác nhận chứng thực của Acme, và cuối cùng Verisign xác nhận chứng thực của WidgetCertificates, bạn nên nhập khẩu chứng thực Acme ngay sau WidgetCertificates. Chứng thực Acme có thể là MIDlet–Certificate–1–2 và của WidgetCertificates có thể là MIDlet–Certificate–1–3.
Chú ý: Bạn không nhập khẩu chứng thực của root CA (đó là chứng thực ở cuối dãy, trong ví dụ này là chứng thực của Verisign). Khóa công cộng của CA sẽ ở trên thiết bị.
Bước 4: Sử dụng tiện ích JadTool để nhận dạng tệp JAR
Tiện ích JadTool sẽ nhận dạng tệp JAD, chữ ký mã hóa 64bit, và lưu trữ nó ở trị số của thuộc tính đầu ra tệp JAD là MIDlet–Jar–RSA–SHA1.
Chú ý: Phải chắc chắn là chìa khóa mà bạn sử dụng để nhận dạng tệp JAR là lấy từ mục nhập keystore JCA, đó là cặp chìa khóa được đề cập ở bước 1. Tiện ích JadTool không kiểm tra khi bạn đang nhận dạng tệp JAR với một mục nhập keystore, đó là một chứng thực trong tệp JAD.
Ví dụ:
c:\MyMIDlet\classes> java -jar ../bin/JadTool.jar -addjarsig -keystore ../bin/j2se_test_keystore.bin -alias dummyca -storepass keystorepwd -keypass keypwd -jarfile HelloMIDlet.jar -inputjad HelloMIDlet.jad -outputjad HelloMIDlet.jad
Phần V
Phát hành MIDlet
Để phát hành một bộ MIDlet, ta đưa nó lên một web server để người sử dụng có thể tải về. Việc phát hành được thực hiện theo các bước sau:
Bảo đảm rằng web server được cấu hình theo cam kết MIME cho các tệp JAR và JAD
Kiểu MIME cho một tệp JAD như sau:
text/vnd.sun.j2me.app-descriptor
Kiểu MIME cho một tệp JAR như sau:
application/java-archive
Đặt các tệp JAR và JAD vào trong một thư mục mà web server có thể truy xuất
Tạo một tệp HTML chứa liên kết tới tệp JAD của bạn
Tệp HTML cung cấp cho người sử dụng cách thức để tìm kiếm và tải về MIDlet của bạn. Công việc tìm kiếm và tải về một MIDlet được gọi là OTA (over the air provisioning).
Tệp HTML không yêu bất cứ cách bố trí hay một cái tên cụ thể nào. Khi người sử dụng thực thi midp để tìm kiếm và tải về các MIDlet, họ có thể nhập vào một URL và MIDP sẽ chỉ hiển thị những kết nối tới URL đó. Nó sẽ bỏ qua phần còn lại trong trang HTML đó.
Ví dụ, trang get–hello.html của MIDlet Hello có thể trông đơn giản như sau:
The Hello MIDlet
<a href=""
>Hello MIDlet
Chú ý: Mặc dù không bắt buộc định dạng cụ thể cho tệp HTML, song khoảng trắng trong tệp có thể ảnh hưởng đến cách bài trí tên của bộ MIDlet trên thiết bị. Ví dụ, nếu tệp HTML có từ liên kết là “Hello MIDlet” thì sẽ xuất hiện dấu xuống dòng giữa hai từ Hello và MIDlet, hiển thị giống như trên thiết bị mô phỏng:
Hình 8: Khoảng trắng trong một trang HTML được hiển thị trên một thiết bị.
Đặt tệp HTML vào trong thư mục hiển thị của web server
Kiểm tra liên kết từ trang HTML tới tệp JAD, và từ tệp JAD tới tệp JAR
Có một cách để thực hiện việc này là chạy thiết bị mô phỏng.
Phần Vi
Xác định vị trí và sửa chữa lỗi
Thực thi tham chiếu MIDP cung cấp cho nền tảng Java các cấp độ gỡ lỗi thông qua cấu trúc gỡ lỗi CLDC (xem tài liệu mô tả cấu trúc gỡ lỗi trong tài liệu CLDC). Trong phần này chỉ đề cập ngắn gọn các bước mà bạn có thể sử dụng cấu trúc và báo cáo các vấn đề gặp phải.
Gỡ lỗi MIDlet
Trước khi gỡ lỗi một MIDlet, bạn phải có các phiên bản thực thi MIDP và MIDlet, đó là các biểu hiện gỡ lỗi trong các tệp class của chúng. Để biết phiên bản mà bạn đang nắm giữ có được midp thừa nhận hay không, bạn thực hiện lệnh midp với tùy chọn –help.
Nếu khi thực thi ngôn ngữ lập trình Java có khả năng gỡ lỗi, bạn sẽ thấy được danh sách các tùy chọn –debugger. Ví dụ:
C:\midp2.0fcs> bin\midp -help
Usage: midp []
Run the Graphical MIDlet Suite Manager.
...
or midp [] -debugger ...
Nếu phiên bản thực thi midp mà bạn đang sử dụng không hỗ trợ gỡ lỗi ngôn ngữ lập trình Java hãy xem các câu lệnh được miêu tả trong mục Porting MIDP (do Sun cung cấp).
Để tạo một phiên bản MIDlet chứa các biểu hiện gỡ lỗi, sử dụng tùy chọn –g trong câu lệnh javac (để biết thêm thông tin xin xem thêm tài liệu nền tảng Java).
Các bước thực hiện gỡ lỗi một MIDlet:
Bước 1: Mở một cửa sổ lệnh (DOS-Command Prompt).
Bước 2: Chuyển tới thư mục hiện thời midpInstallDir.
Ví dụ, nếu Thực thi tham chiếu MIDP được cài đặt trong thư mục c:\midp2.0fcs, bạn có thể chạy câu lệnh:
c:\> cd midp2.0fcs
Bước 3: Khởi động trình thực thi tham chiếu MIDP trong chế độ gỡ lỗi
Sử dụng câu lệnh midp với việc chuyển tùy chọn –debugger và –port. Số hiệu cổng có thể là 2800, đây là số hiệu cổng của proxy trên KVM, nơi trình gỡ lỗi đang chạy (xem tài liệu KVM để biết thêm thông tin về proxy gỡ lỗi).
Ví dụ:
c:\midp2.0fcs\> bin\midp -debugger -port 2800 -classpath classes example.pushpuzzle.PushPuzzle
Bước 4: Khởi động proxy gỡ lỗi
Xem tài liệu KVM để biết thêm thông tin về các tùy chọn, các tham số và cú pháp chính xác. Ví dụ, thực hiện câu lệnh sau trên proxy KVM để kết nối với thực thi midp mà bạn đã khởi động ở bước trước và sau đó lắng nghe ở cổng 5000:
c:\midp2.0fcs\> java -jar c:/kvm/bin/kdp.jar kdp.KVMDebugProxy -l 5000 -p -r localhost 2800 -cp pathsIncludingMIDletClassFiles
Bước 5: Kết nối với proxy gỡ lỗi KVM từ bất kỳ một trình gỡ rối nào đó đều phải tuân theo cấu trúc gỡ lỗi của nền tảng Java
Các trình gỡ lỗi phục tùng bao gồm jdb, SunTM One Studio (trước đó là ForteTM dành cho Java), Jbuilder, Code Warrior, Visual Cafộ, và còn nhiều trình gỡ lỗi khác. Bạn xem tài liệu về các trình gỡ lỗi được đính kèm khi chạy VM trên cổng 5000 của localhost.
Tường trình các vấn đề gặp phải
Bạn có thể gửi các thông tin phản hồi tổng quát, các câu hỏi hay các chú thích tới địa chỉ mail: midp–comments@sun.com. Nếu bạn cho rằng chương trình có lỗi, trước hết hãy kiểm tra những lỗi được phô bày để xem các vấn đề gặp phải đã thực sự được báo cáo hay chưa. Bạn có thể tìm các lỗi trực quan thường có tại địa chỉ:
Nếu phát hiện được lỗi nên sao chép, phân tích và cố định những lỗi đó. Để thực hiện được việc này hãy thu thập các thông tin sau:
Tất cả các nền tảng và thông tin khác nhau, nếu không xây dựng được trên nền tảng chuẩn.
Mô tả lỗi.
Một số thông điệp báo lỗi, các ngoại lệ, dấu vết ngăn xếp, hoặc dữ liệu khác mà bạn đã thu được.
Nếu có thể, dùng kịch bản hoặc đoạn mã biểu thị cho vấn đề gặp phải.
Nhập thông tin về một lỗi trong báo cáo vào URL sau:
Phần ứng dụng
xây dựng chương trình tra cứu tỷ giá hối đoái
Giới thiệu
Chương trình này được viết theo mô hình khách/chủ, thông thường được phân ra thành 2 phần: Một phần được viết để chạy trên máy chủ, phần còn lại được viết để chạy trên máy khách.
Chương trình ở máy khách là một MIDlet, thực hiện các nhiệm vụ sau:
Kết nối với máy chủ (qua giao thức Http).
Nhận yêu cầu do người dùng nhập vào từ bên ngoài.
Gửi yêu cầu đến server để server xử lý.
Trình bày nội dung được trả về từ máy chủ cho người dùng xem.
Chương trình ở máy chủ là một trang JSP (Java Server Pages), thực hiện các nhiệm vụ sau:
Lắng nghe các kết nối từ máy khách gửi đến.
Tiếp nhận những yêu cầu từ phía máy khách.
Xử lý các yêu cầu và gửi trả kết quả về cho máy khách.
Như vậy, chương trình ở máy chủ đóng vai trò như một dịch vụ (service) phục vụ cho máy khách.
Xây dựng chương trình
Các tệp mã chương trình phía máy khách (MIDlet):
Tệp About.java
package mygroup;
import javax.microedition.lcdui.*;
public class About {
/** Copyright notice */
private static String copyright =
"Copyright: \n"+"This product is written by the Group 1, including the members:" + "\n\n"
+ " " + "Văn Minh, Nguyễn (group leader)" + "\n"
+ " " + "Trung Hiếu, Nguyễn" + "\n"
+ " " + "Mạnh Dũng, Nguyễn" + "\n"
+ " " + "Tựng Giang, Nguyễn" + "\n"
+ " " + "Đức Anh, Nguyễn" + "\n"
+ " " + "Đức Lõn, Nguyễn" + "\n"
+ " " + "Ngọc Quang, Nguyễn" + "\n"
+ " " + "Cảnh Dương, Bựi" + "\n"
+ " " + "Văn Thuận, Tạ"
+ "\n\n";
private About() {};
/**
* Đưa ra alert About khi người sử dụng nhấp đồng ý quay về
* màn hỡnh trước đú.
* display – tham số Display để quay trở về khi
* màn hỡnh about được giải phúng.
*/
public static void showAbout(Display display) {
Alert alert = new Alert("About this MIDlet");
alert.setTimeout(Alert.FOREVER);
// thờm vào alert nội dung copyright
alert.setString(copyright);
display.setCurrent(alert);
}
}
Tệp HttpView.java (MIDlet)
package mygroup;
import javax.microedition.midlet.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
import java.lang.String;
/**
* Đõy là một vớ dụ về MIDlet sử dụng một kết nối Http để lấy về
* nội dung của một trang.
* Thực hiện cỏc phương thức startApp, pauseApp, và destroyApp
* để xem MIDlet quản lý mỗi giao dịch yờu cầu như thế nào.
* Lớp HttpView kế thừa (extends) từ gúi javax.microedition.midlet.MIDlet và
* thực thi đầy đủ cỏc phương thức CommandListener, Runnable
* Chỳ ý: Sau từ khúa extends chỉ cú một lớp được khai bỏo,
* cũn sau từ khúa implements
* cú thể khai bỏo nhiều phương thức trong cỏc gúi API.
*/
public class HttpView extends MIDlet implements CommandListener, Runnable {
/** Cõu lệnh giao diện người sử dụng dành để đưa ra yờu cầu thoỏt. */
Command exitCommand = new Command("Exit", Command.EXIT, 2);
/**Cõu lệnh giao diện người sử dụng dựng để đưa ra yờu cầu nạp lại một trang. */
Command reloadCommand = new Command("Reload", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để yờu cầu một giao dịch Http HEAD. */
Command headCommand = new Command("Head", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để yờu cầu một giao dịch Http POST. */
Command postCommand = new Command("Post", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để yờu cầu một giao dịch Http GET. */
Command getCommand = new Command("Get", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để yờu cầu thụng tin bản quyền. */
Command aboutCommand = new Command("About", Command.HELP, 1);
/** Cõu lệnh giao diện người sử dụng để hủy bỏ màn hỡnh hiện thời. */
Command cancelCommand = new Command("Cancel", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để quay trở về màn hỡnh trước đú. */
Command backCommand = new Command("Back", Command.BACK, 1);
/** Cõu lệnh giao diện người sử dụng để yờu cầu cỏc header Http hiện thời. */
Command headersCommand = new Command("Headers", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để hiển thị cỏc header yờu cầu
* Http hiện thời. */
Command requestsCommand = new Command("Requests", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để hiển thị cỏc lỗi từ yờu cầu hiện thời.*/
Command errorsCommand = new Command("Errors", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để nhập vào một URL mới. */
Command newURLCommand = new Command("New URL", Command.SCREEN, 10);
/** Cõu lệnh giao diện người sử dụng để gỡ bỏ URL hiện thời. */
Command removeURLCommand = new Command("Remove", Command.SCREEN, 11);
/** Cõu lệnh giao diện người sử dụng để xỏc nhận màn hỡnh hiện thời. */
Command okCommand = new Command("OK", Command.SCREEN, 1);
/** Cõu lệnh giao diện người sử dụng để hiển thị thụng điệp trợ giỳp. */
Command helpCommand = new Command("Help", Command.HELP, 1);
/** Dựng để chứa một danh sỏch cỏc thành phần giao diện người sử dụng. */
List urlList;
/** Mảng chứa cỏc URL hiện thời. */
Vector urls;
/**Thành phần cảnh bỏo giao diện người sử dụng. */
Alert alert;
/**Dựng một textbox để hiển thị nội dung lấy về từ URL. */
TextBox content;
/** current display. */
Display display;
/**Đưa ra một luồng dành cho mạng khụng đồng bộ với giao diện người dựng. */
Thread thread;
/**URL được yờu cầu hiện thời. */
String url;
/** Kiểu yờu cầu Http hiện thời - GET, HEAD, hay POST */
Command requestCommand;
/** form giao diện người dựng để lưu giữ kết quả tiến trỡnh. */
Form progressForm;
/**Chỉ bỏo tiến trỡnh giao diện người dựng. */
Gauge progressGauge;
/**màn hỡnh giao diện người dựng để chứa cỏc header Http. */
Form headerForm;
/** Form để hiển thị yờu cầu, bao gồm cả việc phõn tớch từ loại. */
Form requestForm;
/**Form dựng để hiển thị cỏc lỗi ngoại lệ. */
Form errorsForm;
/** textbox nhập liệu dựng để nhập cỏc URL. */
TextBox urlbox;
/**Khởi tạo MIDlet với đối tượng hiển thị hiện thời. */
public HttpView() {
/**lấy màn hỡnh hiển thị hiện thời. */
display = Display.getDisplay(this);
/**gọi phương thức thiết lập danh sỏch cỏc cõu lệnh. */
setupList();
/**đưa ra một cảnh bỏo. */
alert = new Alert("Warning");
alert.setTimeout(2000);
/**khai bỏo đối tượng form “Headers”. */
headerForm = new Form("Headers");
/**gắn cõu lệnh “Back” vào form “Headers”. */
headerForm.addCommand(backCommand);
/**gắn cõu lệnh “Requests” vào form “Headers”. */
headerForm.addCommand(requestsCommand);
/**Thiết lập lắng nghe sự kiện cõu lệnh lờn form “Headers”. */
headerForm.setCommandListener(this);
/**khai bỏo đối tượng form “Request headers”. */
requestForm = new Form("Request headers");
/**gắn cõu lệnh “Back” vào form “Request headers”. */
requestForm.addCommand(backCommand);
/**gắn cõu lệnh “Errors” vào form “Request headers”. */
requestForm.addCommand(errorsCommand);
/**Thiết lập lắng nghe sự kiện cõu lệnh lờn form “Request headers”. */
requestForm.setCommandListener(this);
/**khai bỏo đối tượng form “Progress”. */
progressForm = new Form("Progress");
/**gắn cõu lệnh “Cancel” vào form “Progress”. */
progressForm.addCommand(cancelCommand);
/**Thiết lập lắng nghe sự kiện cõu lệnh lờn form “Progress”. */
progressForm.setCommandListener(this);
/**khai bỏo đối tượng Gauge (tương tự như ProgressBar ở windows)
* với cỏc tham số chuỗi url,
* tham số logic tương tỏc(true/false), kớch thước lớn nhất,
*kớch thước khởi đầu.
*/
progressGauge = new javax.microedition.lcdui.Gauge(url, false, 9, 0);
/**Đưa thanh tiến trỡnh Gauge lờn form. */
progressForm.append(progressGauge);
/**khai bỏo form “Errors”. */
errorsForm = new Form("Errors");
/**gắn lệnh “Back” lờn form “Errors”. */
errorsForm.addCommand(backCommand);
/**gắn cõu lệnh “Headers” lờn form “Errors”. */
errorsForm.addCommand(headersCommand);
/**Thiết lập lắng nghe sự kiện cõu lệnh lờn form “Errors”. */
errorsForm.setCommandListener(this);
/**khai bỏo một textbox để nhập vào một URL, độ rộng textbox 400, kiểu URL. */
urlbox = new TextBox("Enter Url", "http://", 400, TextField.URL);
/**gắn cõu lệnh “OK” lờn đối tượng urlbox. */
urlbox.addCommand(okCommand);
/**Thiết lập lắng nghe sự kiện cõu lệnh lờn đối tượng urlbox. */
urlbox.setCommandListener(this);
}
/**
*Khởi động MIDlet và tạo luồng làm việc.
*
*/
public void startApp() {
if (urlList.size() > 0) {
display.setCurrent(urlList);
} else {
alert.setString("No url's configured.");
display.setCurrent(alert, urlList);
}
}
/**
* Phương thức pauseApp() đưa ra dấu hiệu để dừng luồng bằng
* cỏch xúa trường luồng.
* Nếu dừng trước khi làm việc với cỏc tương tỏc, nú sẽ được khởi động từ đầu..
*/
public void pauseApp() {
}
/**
* Giải phúng phải xúa bỏ mọi thứ. Luồng cú dấu hiệu dừng và
* khụng cú kết quả được đưa ra.
* Tham số logic unconditional là true nếu một ngắt sẵn sàng đó được yờu cầu
*/
public void destroyApp(boolean unconditional) {
thread = null;
}
/**
* Kiểm tra cỏc thuộc tớnh trong phần mụ tả để nhận dạng
*cỏc tiờu đề của url và khởi tạo danh sỏch cỏc url.
*
* Cỏc thuộc tớnh tờn gọi “ViewTitle –n” và “ViewURL –n”..
* Giỏ trị “n” phải bắt đầu từ “1” và mỗi bước tăng lờn 1 giỏ trị.
*/
void setupList() {
/**khai bỏo mảng theo dạng vector dựng để chứa cỏc url. */
urls = new Vector();
/**khai bỏo danh sỏch cỏc url theo kiểu ẩn. */
urlList = new List("URLs", List.IMPLICIT);
/**gỏn cỏc lệnh lờn urlList. */
urlList.addCommand(headCommand);
urlList.addCommand(getCommand);
urlList.addCommand(postCommand);
urlList.addCommand(exitCommand);
urlList.addCommand(newURLCommand);
urlList.addCommand(removeURLCommand);
urlList.addCommand(helpCommand);
urlList.addCommand(aboutCommand);
/**Thiết lập bộ lăng nghe sự kiện cho lựa chọn cõu
* lệnh trờn danh sỏch urlList. */
urlList.setCommandListener(this);
/**đưa vào một phần tử url để kiểm tra kết nối,
* nhưng chuỗi url để ẩn mà chỉ hiện "Test URL".
*/
urls.addElement("");
urlList.append("Test URL", null);
}
/**
* Phương thức phản hồi lại cỏc cõu lệnh, bao gồm lệnh thoỏt
* c - tham số yờu cầu cõu lệnh của người sử dụng
* s là đối tượng ban đầu yờu cầu được hiển thị trờn màn hỡnh
*/
public void commandAction(Command c, Displayable s) {
try {
/**
* nếu cõu lệnh yờu cầu là exitCommand thỡ giải phúng MIDlet.
* cũn nếu khụng phải là exitCommand thỡ thực hiện cỏc cõu lệnh
* trong List.
*/
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
} else if (c == headCommand ||
c == getCommand ||
c == postCommand ||
c == List.SELECT_COMMAND) {
if (c == List.SELECT_COMMAND)
c = getCommand;
requestCommand = c;
// Hiển thị màn hỡnh tiến trỡnh và
// khởi động luồng để đọc url
int i = urlList.getSelectedIndex();
url = (String)urls.elementAt(i);
//gọi phương thức sinh form tiến trỡnh của url
genProgressForm("Progress", url);
//Thiết lập form tiến trớnh làm form hiển thị hiện thời
//được gắn lờn đối tượng display.
display.setCurrent(progressForm);
//tạo luồng mới
thread = new Thread(this);
//khởi động luồng vừa tạo.
thread.start();
} else if (c == headersCommand) {
display.setCurrent(headerForm);
} else if (c == requestsCommand) {
display.setCurrent(requestForm);
} else if (c == errorsCommand) {
display.setCurrent(errorsForm);
} else if (c == backCommand) {
if (s == headerForm || s == requestForm ||
s == errorsForm)
{
display.setCurrent(content);
} else {
// Hiển thị danh sỏch cỏc url.
display.setCurrent(urlList);
}
} else if (c == cancelCommand) {
// Dấu hiệu dừng luồng và đưa ra cảnh bỏo.
thread = null;
alert.setString("Loading cancelled.");
display.setCurrent(alert, urlList);
} else if (c == aboutCommand) {
About.showAbout(display);
} else if (c == newURLCommand) {
display.setCurrent(urlbox);
} else if (c == removeURLCommand) {
int i = urlList.getSelectedIndex();
urlList.delete(i);
urls.removeElementAt(i);
} else if (c == okCommand && s == urlbox) {
String newurl = urlbox.getString();
urlList.append(newurl, null);
urls.addElement(newurl);
display.setCurrent(urlList);
} else if (c == helpCommand) {
String helpString =
"Use HEAD, GET or POST to download a URL.\n\n" +
"Use 'New URL' to enter a new URL.";
Alert alert = new Alert(null, helpString, null, null);
alert.setTimeout(Alert.FOREVER);
display.setCurrent(alert);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Lấy về một url đó được chỉ định trong một luồng tỏch rời và cập nhật
* thanh tiến trỡnh khi đang chạy.
* Nếu người dựng hủy bỏ khụng lấy, luồng bị thay đổi từ luồng này.
* Nếu điều đú xảy ra mà khụng cập nhật được thờm thỡ cỏc form sẽ
* hiển thị. Cỏc đối tượng chia sẻ cú thể được sử dụng lại
* cho kết nối lần sau.
*/
public void run() {
Thread mythread = Thread.currentThread();
String method = HttpConnection.GET;
if (requestCommand == headCommand) {
method = HttpConnection.HEAD;
} else if (requestCommand == postCommand) {
method = HttpConnection.POST;
}
if (content == null) {
content = new TextBox("Content", "", 4096, 0);
content.addCommand(backCommand);
content.addCommand(headersCommand);
content.setCommandListener(this);
}
/** Xúa cỏc form và bộ nhớ đệm sau khi đó được hiển thị
* thậm chớ sau khi kết thỳc quỏ trỡnh đọc, nếu cú ngoại
* lệ thỡ đưa ra.
*/
content.setTitle("Response Results");
content.setString("");
genErrorsForm("Errors", null);
clearForm(requestForm);
clearForm(headerForm);
//Thiết lập giỏ trị cho thanh tiến trỡnh
progressGauge.setValue(1);
//khởi tạo giỏ trị ban đầu cho kết nối là null
HttpConnection conn = null;
//dũng vào là null
InputStream input = null;
//dũng ra là null
OutputStream output = null;
//tạo bộ đệm
StringBuffer b;
String string = null;
try {
//khai bỏo biến len (độ dài của xõu).
long len = 0;
//mở kết nối tới url.
conn = (HttpConnection)Connector.open(url);
//Thiết lập phương thức yờu cầu cho kết nối.
conn.setRequestMethod(method);
//gọi phương thức cấu hỡnh
setConfig(conn);
if (mythread != thread) {
return;
}
progressGauge.setValue(2);
for (int hops = 0; hops < 2; hops++) {
// Gởi dữ liệu đến server (nếu cần thiết). Khi đú, nếu thấy
// một địa chỉ url mới nú sẽ nhảy đến URL mới được
// chỉ định bởi server.
//
// Bạn cú thể chọn lựa để cỏc hop (bước truyền) để tạo ra
// điều kiện thoỏt cho vũng lặp.
//
// Để xem một vớ dụ, cố gắng kết nối tới địa chỉ:
// "" link, nú sẽ
// hướng bạn đến một liờn kết với một ID session.
if (method == HttpConnection.POST) {
output = conn.openOutputStream();
if (mythread != thread) {
return;
}
output.write("Hello MIDlet world".getBytes());
output.close();
output = null;
}
HttpConnection newConn = handleRedirects(conn);
if (conn != newConn) {
conn = newConn;
} else {
break;
}
}
//gọi phương thức sinh form yờu cầu kết nối
genRequestForm(conn);
input = conn.openInputStream();
if (mythread != thread) {
return;
}
content.setTitle(conn.getResponseMessage() +
" (" + conn.getResponseCode() + ")");
genHeaderForm(conn);
progressGauge.setValue(5);
if (mythread != thread) {
return;
}
// Tải về nội dung của URL. Giới hạn tải về
// là 4096 byte (content.getMaxSize()), khi mà hầu hết
// cỏc thiết bị nhỏ cú thể khụng cú khả năng kiểm soỏt kớch thức lớn hơn.
//
// Một chương trỡnh thực tế cần phải kiểm soỏt được nguồn tải về một cỏch
// thụng minh. Nếu cú thể nú sẽ làm việc với server để giới hạn
// cho kớch thức nhỏ. Nếu điều này là khụng thể, thỡ nú chỉ
// tải về một phần
// dữ liệu và cho phộp người dựng chỉ định phần tải về.
len = conn.getLength();
b = new StringBuffer(len >= 0 ? (int)len : 1000);
int max = content.getMaxSize();
if (len != -1) {
// Đọc chiều dài nội dung theo byte, hoặc đó đọc tới vị trớ lớn nhất.
int ch = 0;
for (int i = 0; i < len; i++) {
if ((ch = input.read()) != -1) {
if (ch <= ' ') {
ch = ' ';
}
b.append((char) ch);
if (b.length() >= max) {
break;
}
}
}
} else {
// Đọc khi kết nối đó được đúng, hoặc đó đọc tới vị trớ lớn nhất.
// (kịch bản HTTP/1.0 điển hỡnh được sinh ra ở đầu ra)
int ch = 0;
len = 0;
while ((ch = input.read()) != -1) {
if (ch <= ' ') {
ch = ' ';
}
b.append((char)ch);
if (b.length() >= max) {
break;
}
}
}
string = b.toString();
if (mythread != thread) {
return;
}
progressGauge.setValue(8);
content.setTitle("BODY Len = " + b.length());
if (b.length() > 0) {
content.setString(string);
} else {
content.setString("No data");
}
display.setCurrent(content);
progressGauge.setValue(9);
} catch (OutOfMemoryError mem) {
/** Cú thể tràn bộ nhớ, ngay cả khi thiết lập dung lượng lớn nhất tải về
* là 4096 byte. Thụng bỏo lỗi cho người dựng.
*
* Một chương trỡnh thực tế sẽ quyết định chọn kớch thước lớn nhất
* để tải về phục thuộc vào khụng gian cú sẵn của bộ nhớ heap, hoặc cú thể
* cho phộp người sử dụng thiết lập kớch thước lớn nhất.
*/
b = null;
content = null; // bộ nhớ trống để in lỗi
// DEBUG: System.out.println("Out of Memory");
mem.printStackTrace();
if (mythread != thread) {
genErrorsForm("Memory", mem);
display.setCurrent(errorsForm);
}
} catch (Exception ex) {
ex.printStackTrace();
genErrorsForm("Errors", ex);
display.setCurrent(errorsForm);
} finally {
cleanUp(conn, input, output);
if (mythread == thread) {
progressGauge.setValue(10);
}
}
}
/**
* Phương thức này xúa tất cả cỏc đối tượng được sử dụng bởi HttpConnection.
* Chỳng ta phải đúng cỏc đối tượng OutputStream, InputStream, cũng như đối tượng
* HttpConnection, để phục hồi tài nguyờn hệ thống. Mặt khỏc,
* chỳng ta cú thể khụng cú khả năng tạo ra cỏc kết nối mới trờn một
* vài nền tảng.
*
* Conn - tham số HttpConnection
* input là InputStream của HttpConnection, cú thể rỗng
* nếu nú chưa được mở.
* output là OutputStream của HttpConnection, cú thể rỗng
* nếu nú chưa được mở.
*/
void cleanUp(HttpConnection conn, InputStream input,
OutputStream output)
{
Thread mythread = Thread.currentThread();
try {
if (input != null) {
input.close();
}
} catch (IOException e) {
if (mythread == thread) {
genErrorsForm("InputStream close error", e);
}
}
try {
if (output != null) {
output.close();
}
} catch (IOException e) {
if (mythread == thread) {
genErrorsForm("OutStream close error", e);
}
}
try {
if (conn != null) {
conn.close();
}
} catch (IOException e) {
if (mythread == thread) {
genErrorsForm("HttpConnection close error", e);
}
}
}
/**
* Kiểm tra để gửi lại lần nữa cỏc mó phản hồi và điều khiển
* gửi lại lần nữa bằng cỏch khai thỏc vị trớ mới và
* mở ra một kết nối cho nú. Kết nối gốc được đúng.
* Quy trỡnh này vẫn lặp lại cho đến khi khụng cũn gửi lại nữa.
* c - tham số khởi tạo HttpConnection
* trả về HttpConnection cuối cựng.
*/
HttpConnection handleRedirects(HttpConnection c) throws IOException {
while (true) {
int code = c.getResponseCode();
switch (code) {
case HttpConnection.HTTP_TEMP_REDIRECT:
case HttpConnection.HTTP_MOVED_TEMP:
case HttpConnection.HTTP_MOVED_PERM:
String loc = c.getHeaderField("location");
c.close();
// DEBUG: System.out.println("Redirecting to " + loc);
showAlert("Redirecting to " + loc, null);
progressGauge.setLabel(loc);
c = (HttpConnection)Connector.open(loc);
// TBD: Copy request properties
continue;
default:
return c;
}
}
}
/**
* Thờm cỏc đặc tớnh yờu cầu cho cấu hỡnh, cỏc đặc tả,
* và cục bộ của hệ thống.
* c - tham số HttpConnection hiện tại để nhận header
*/
void setConfig(HttpConnection c) throws IOException {
String conf = System.getProperty("microedition.configuration");
String prof = System.getProperty("microedition.profiles");
int space = prof.indexOf(' ');
if (space != -1) {
prof = prof.substring(0, space - 1);
}
String platform = System.getProperty("microedition.platform");
String locale = System.getProperty("microedition.locale");
String ua = "Profile/" + prof +
" Configuration/" + conf +
" Platform/" + platform;
// DEBUG: System.out.println("User-Agent: " + ua);
c.setRequestProperty("User-Agent", ua);
if (locale != null) {
// DEBUG: System.out.println("Content-Language: " + locale);
c.setRequestProperty("Content-Language", locale);
}
}
/**
* Tạo ra và lấp đầy Form bằng cỏc trường header.
* c - tham số kết nối mở với kết quả là cỏc header.
*/
void genHeaderForm(HttpConnection c) throws IOException {
clearForm(headerForm);
headerForm.append(new StringItem("response message: ",
c.getResponseMessage()));
headerForm.append(new StringItem("response code: ",
c.getResponseCode() + ""));
for (int i = 0; ; i++) {
String key = c.getHeaderFieldKey(i);
if (key == null)
break;
String value = c.getHeaderField(i);
StringItem item = new StringItem(key + ": ", value);
headerForm.append(item);
}
}
/**
* Tạo ra Form với cỏc thuộc tớnh yờu cầu và cỏc giỏ trị.
* c - tham số kết nối mở với cỏc header yờu cầu.
*/
void genRequestForm(HttpConnection c) throws IOException {
clearForm(requestForm);
requestForm.append(new StringItem("URL: ",
c.getURL()));
requestForm.append(new StringItem("Method: ",
c.getRequestMethod()));
requestForm.append(new StringItem("Protocol: ",
c.getProtocol()));
requestForm.append(new StringItem("Host: ",
c.getHost()));
requestForm.append(new StringItem("File: ",
c.getFile()));
requestForm.append(new StringItem("Ref: ",
c.getRef()));
requestForm.append(new StringItem("Query: ",
c.getQuery()));
requestForm.append(new StringItem("Port: ",
Integer.toString(c.getPort())));
requestForm.append(new StringItem("User-Agent: ",
c.getRequestProperty("User-Agent")));
requestForm.append(new StringItem("Content-Language: ",
c.getRequestProperty("Content-Language")));
}
/**
* Tạo ra Form cú cỏc tựy chọn với tiờu đề URL và thanh tiến trỡnh.
* name - tham số tiờu đề của URL được nạp vào.
* url - tham số nhón dành cho thanh tiến trỡnh. */
void genProgressForm(String name, String url) {
progressGauge.setValue(0);
progressGauge.setLabel(url);
progressForm.setTitle(name);
}
/**
* Thiết lập cảnh bỏo đối với thụng điệp ngoại lệ và hiển thị nú.
* s - tham số chuỗi tiờu đề ngoại lệ.
* ex - tham số ngoại lệ
*/
void genErrorsForm(String s, Throwable ex) {
clearForm(errorsForm);
if (s != null) {
errorsForm.setTitle(s);
} else {
errorsForm.setTitle("Exception");
}
if (ex != null) {
ex.printStackTrace(); // debug
errorsForm.append(ex.getClass().getName());
errorsForm.append("\n");
String m = ex.getMessage();
if (m != null) {
errorsForm.append(m);
}
} else {
errorsForm.append("None");
}
}
/**
* Thiết lập chuỗi cảnh bỏo và hiển thị nú.
* s - tham số thụng điệp lỗi.
* next - tham số màn hỡnh được hiển thị sau Alert.
*/
void showAlert(String s, Screen next) {
alert.setString(s);
if (next == null) {
display.setCurrent(alert);
} else {
display.setCurrent(alert, next);
}
}
/**
* Loại bỏ tất cỏc đối tượng trong một Form.
* form - tham số Form để xúa.
*/
void clearForm(Form form) {
int s = form.size();
for (int i = s-1; i >= 0; i--) {
form.delete(i);
}
}
}
Phụ lục A
Mã nguồn đầy đủ của MIDlet Hello:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
* Một vớ dụ MIDlet với dũng văn bản “Hello” và một cõu lệnh thoỏt.
*/
public class HelloMIDlet extends MIDlet implements CommandListener {
// Cỏc trường dành cho màn hỡnh, cõu lệnh, và hiển thị của MIDlet
private Command exitCommand;
private TextBox textBox;
private Display display;
public HelloMIDlet() {
// Tạo cõu lệnh trừu tượng
exitCommand = new Command("Exit", Command.EXIT, 1);
// Tạo đối tượng textbox và đưa vào đú một cõu lệnh và bộ lắng nghe sự kiện
textBox = new TextBox("Hello MIDlet", "Test string", 256,
TextField.ANY | TextField.UNEDITABLE);
textBox.addCommand(exitCommand);
textBox.setCommandListener(this);
// Thiết lập màn hỡnh khởi tạo cho MIDlet
display = Display.getDisplay(this);
display.setCurrent(textBox);
}
/**
* Khởi động MIDlet; phương thức này khụng làm gỡ bởi vỡ
* MIDlet này khụng yờu cầu chia sẻ tài nguyờn.
*/
public void startApp() {
}
/**
* Tạm dừng MIDlet; phương thức này khụng thực hiện gỡ bởi vỡ khụng cú
* cỏc hoạt động nền hay đúng nguồn tài nguyờn chia sẻ.
*/
public void pauseApp() {
}
/**
* Giải phúng MIDlet; phương thức này khụng thực hiện việc gỡ bởi vỡ
* khụng cú gỡ để dọn dẹp mà cũng khụng bị kiểm soỏt bởi trỡnh thu gom rỏc.
*/
public void destroyApp(boolean unconditional) {
}
/*
* Phản hồi lại cỏc lựa chọn cõu lệnh trừu tượng của người dựng.
* MIDlet này chỉ cú duy nhất một cõu lệnh thoỏt. Phương thức này
* phản hồi để dọn dẹp và thụng bỏo cho hệ thống rằng
* MIDlet đó được giải phúng.
*/
public void commandAction(Command command, Displayable screen) {
if (command == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}
}
Tài liệu tham khảo
Lập trình Java, Khoa CNTH, Viện ĐH Mở Hà Nội.
Learning Wireless Java, NXB O’Reilly 12/2001.
JavaTM Network Programming and Distributed Computing, NXB Addison Wesley 25/03/2002.
Beginning Java 2 JDK6 Edition, NXB Addison Wesley, 2007.
Programming Wireless Devices with the J2ME Core J2ME Technology & MIDP, NXB Prentice Hall.
MIDP 2.0, Sun Microsystems, Inc.
and developing Resources on Intern
Các file đính kèm theo tài liệu này:
- 7942.doc