2008.06_Java Microedition – metody integracji aplikacji_[Inzynieria Oprogramowania].pdf

(573 KB) Pobierz
441663205 UNPDF
Inżynieria
oprogramowania
– metody integracji aplikacji
A plikacje Java Microedition (konfiguracji
Albert Wachowicz
CLDC) działające na urządzeniach przeno-
śnych mają zazwyczaj ograniczone zaso-
by sprzętowe. W większości przypadków limitowa-
na pamięć oraz wolne procesory na urządzeniach
powodują, że pewne zadania są mało wydajne lub
niemożliwe do zrealizowania. Rozwiązaniem tego
problemu może być przeniesienie części funkcjo-
nalności aplikacji na stronę serwera. W ten sposób
realizuje się ubogiego klienta, który wymaga mniej
zasobów przy zakładanej funkcjonalności. Nato-
miast serwer przejmuje wymagające większych
zasobów zadania i zwraca do aplikacji klienckiej
tylko rezultaty swojej pracy.
Niniejszy artykuł skupi się na sposobach in-
tegracji aplikacji klienta JME z aplikacją serwera.
Zostanie zaprezentowany krótki przegląd metod
za pomocą których można skomunikować klien-
ta z serwerem.
Gruntownie zostaną opisane wybrane mecha-
nizmy integracji, które obecnie są najczęściej sto-
sowane. Na koniec zostanie przedstawiona ocena
wybranych metod w odniesieniu do wszechstron-
nego zastosowania.
Jednym z lepszych zestawień danych technicz-
nych urządzeń mobilnych różnych producentów
jest strona J2MEPolish.
Kolejnym ważnym aspektem jest profil urzą-
dzenia Mobile Information Device Profile w skró-
Listing 1. Przykładowa metoda wysyłająca
wiadomość poprzez gniazdo
void sendSocketMsg ( String destAddr , String msg ) {
try {
//utworzenie gniazda
SocketConnection client =
( SocketConnection )
Connector . open ( "socket://"
+ destAddr + ":3000" ) ;
//otwarcie strumienii wejscia/wyjscia
InputStream is = client . openInputStr
eam () ;
OutputStream os = client . openOutputSt
ream () ;
// wysłanie wiadomosci doserwera
os . write ( msg . getBytes ()) ;
os . write ( '\n' ) ;
// odczytanie odpowiedzi (dla
przykladu do znaku konca
linii \n lub gdy serwer
zamknie polaczenie)
Uwagi na temat technologii JME
W technologii JME paczki z bibliotekami dostępne
są bezpośrednio w maszynie wirtualnej KVM ( Kilo-
byte Virtual Machine ) urządzenia dzięki czemu pro-
gramista nie musi martwić się o ich dostępność. Z
drugiej strony istnieją rozwiązania, które wymagają
dołączenia odpowiedniej biblioteki zawartej w ar-
chiwum jar . Wiąże się to niestety ze wzrostem roz-
miaru (archiwum jar ) aplikacji co ma istotne zna-
czenia w przypadku limitów maksymalnej wielko-
ści narzuconej przez producentów.
Zagadnienie to nie stanowi jednakże tematu
niniejszego artykułu. Zainteresowanym polecam
strony producentów urządzeń, gdzie w większości
przypadków tego rodzaju informacje są dostępne.
int c = 0 ;
StringBuffer sb = new StringBuffer () ;
while (( c = is . read ()) != - 1 && ( c != '\
n' )) {
sb . append (( char ) c ) ;
}
System . out . println ( "[Serwer]" +
sb . toString ()) ;
//analiza odpowiedzi...
// zamkniecie strumieni oraz
polaczenia
is . close () ;
os . close () ;
client . close () ;
} catch ( IOException ex ) {
ex . printStackTrace () ;
}
}
Albert Wachowicz pracuje na stanowisku Software
Specialist w BLStream wchodzącym w skład Grupy
BLStream. Grupa BLStream powstała by efektywniej
wykorzystywać potencjał dwóch, szybko rozwijają-
cych się producentów oprogramowania – BLStream
i Gamelion. Firmy wchodzące w skład grupy specja-
lizują się w wytwarzaniu oprogramowania dla klien-
tów korporacyjnych, w rozwiązaniach mobilnych oraz
produkcji i testowaniu gier.
Kontakt z autorem: albert.wachowicz@gmail.com
58
www.sdjournal.org
Software Developer’s Journal 6/2008
Java Microedition
441663205.016.png 441663205.017.png
Java Microedition
cie MIDP oraz konfiguracja Connected Limited Device Con-
figuration CLDC. Określa się w nich zbiór interfejsów i klas
dostępnych w danej KVM. Aktualnie dominującym profilem
jest MIDP 2.0 w połączeniu z konfiguracją CLDC 1.1 (lub
1.0). Jednakże istnieją także urządzenia określane mianem
wersji MIDP 1.0. W artykule zostanie zaznaczone od któ-
rej wersji profilu dostępny jest dany mechanizm jeśli bę-
dzie to istotne.
• Komunikacja niskopoziomowa – UDP, TCP, TLS(SSL);
• HTTP/HTTPS;
• RMI – J2MEPolishRMI, implementacja RMI bazująca na
gniazdach;
• XML-RPC – kXMLRPC, J2MEPolishRPC;
• Web Services – kSOAP[5], klient WebServices w NetBe-
ans, JSR-172;
• WMA – SMS/MMS;
• SIP;
• SyncML – kSync, implementacja SyncML;
• Peer2Peer – JXTA;
• Bluetooth;
• Inne:
Spis metod integracyjnych
Biorąc pod uwagę ogólne standardy komunikacji siecio-
wej w JME można wyróżnić między innymi następujące
mechanizmy:
Listing 2. Metoda nasłuchujące na TCP
Listing 3. Przykładowa metoda POST
public void wait4TcpConnection () {
try {
// utworzenie serwera nasluchujacego na porcie
3000
ServerSocketConnection server =
( ServerSocketConnection )
Connector . open ( "socket://:3000" ) ;
// oczekiwanie na polaczenia
System . out . println ( "Oczekiwanie na
polaczenie..." ) ;
SocketConnection client = ( SocketConnection )
server . acceptAndOpen () ;
System . out . println ( "Zaakceptowanie polaczenia z
adresu" + client . getAddress ()) ;
// utworzenie strumienie wejscia/wyjscia
InputStream is = client . openInputStream () ;
OutputStream os = client . openOutputStream () ;
// czytanie danych ze strumienia (dla przykladu
do znaku konca linii \n lub gdy
klient zamknal polaczenie)
private void doSendHTTP ( String request , String url ){
String responseStr = null ;
try
{
//utworzenie polaczenia HTTP i ustawienie
nagłowka
HttpConnection conn = ( HttpConnection ) Connector
. open ( url ) ;
conn . setRequestMethod ( HttpConnection . POST ) ;
conn . setRequestProperty ( "Content-Length" ,
Integer . toString ( reques
t . length ())) ;
//wyslanie wiadomosci
OutputStream out = conn . openOutputStream () ;
int requestLength = request . length () ;
for ( int i = 0 ; i < requestLength ; ++ i ){
out . write ( request . charAt ( i )) ;
}
InputStream in = conn . openInputStream () ;
StringBuffer responseBuf ;
long length = conn . getLength () ;
if ( length > 0 ){
responseBuf = new StringBuffer (( int ) length ) ;
}
else {
responseBuf = new StringBuffer () ;
}
//odczytanie odpowiedzi
int ch ;
while (( ch = in . read ()) != - 1 )
{
responseBuf . append (( char ) ch ) ;
}
responseStr = responseBuf . toString () ;
System . out . println ( responseStr . toString ()) ;
} catch ( IOException e ){
e . printStackTrace () ;
} catch ( SecurityException e ){
e . printStackTrace () ;
}
}
int c ;
StringBuffer sb = new StringBuffer () ;
while ((( c = is . read ()) != - 1 ) && ( c != '\n' )) {
sb . append (( char ) c ) ;
}
System . out . println ( "[KLIENT]" + sb . toString ()) ;
//analiza wiadomosci ...
//wyslanie odpowiedzi
String responseMsg = new String ( "Odpowiedz
serwera OK \n " ) ;
os . write ( responseMsg . getBytes ()) ;
// zamkniecie strumienii oraz polaczenia
is . close () ;
os . close () ;
client . close () ;
server . close () ;
} catch ( IOException ex ) {
ex . printStackTrace () ;
}
}
Software Developer’s Journal 6/2008
www.sdjournal.org
59
441663205.018.png
Inżynieria
oprogramowania
• JSON,
• Burlap,
• JINI,
• GASP,
• OpenDMTP,
• Payment API,
• Jsch.
konkretny obiekt typu Connection . Na Rysunku 1 przedsta-
wiona jest hierarchia interfejsów, które mogą implemen-
tować obiekty zwrócone przez metodę Connector.open() .
Przeźroczysty sposób tworzenia połączenia daje uniwer-
salną metodę, która zgłasza wyjątek ConnectionNotFoun-
dException w przypadku gdy urządzenie nie implementuje
określonego połączenia.
Komunikacja
niskopoziomowa oraz HTTP
Gniazda są mechanizmem komunikacji definiującym inter-
fejs programowania do wymiany informacji. W Java Micro-
edition (MIDP 2.0) można zrealizować połączenia gniazd
wykorzystując UDP, TCP i TLS.
Ogólny szkielet nawiązania połączenia w JME wykony-
wany jest przez następującą metodę fabryki Connector.ope-
n("protocol:address;parameters") z paczki javax.microedi-
tion.io . Metoda zwraca określony przez parametr protocol
TCP
Transmission Control Protocol jest połączeniowym proto-
kołem zapewniającym niezawodną komunikację strumie-
niową. Ustanawia dwukierunkową współpracę między ho-
stami z możliwością sterowania przepływem (Rysunek 2).
Kontroluje poprawność oraz kolejność pakietów danych i
oczekuje potwierdzania ich odbioru.
W przypadku wystąpienia błędów komunikacyjnych po-
trafi przeprowadzić retransmisję. Protokół TCP nie zobo-
wiązuje się jednak na zrealizowanie połączenia w określo-
nym czasie.
Przy nadmiernym obciążeniu łącz daje się zaobserwo-
wać nagłe spowolnienie transmisji. Spowodowane to jest
między innymi błędnymi pakietami i wysyłaniem żądań ich
ponownej retransmisji.
TCP w Java Microedition realizowane jest poprzez wy-
wołanie metody Connector.open oraz określenie minimalnie
parametrów: protocol jako socket oraz address jako adre-
su hosta docelowego wraz z portem. Przykładową metodę
wysyłającą wiadomość typu String na określony adres po-
dany w parametrach wywołania metody jest zaprezentowa-
ny na Listingu 1.
Natomiast aplikacja nasłuchująca i wykorzystująca
gniazda TCP jest przedstawiona na Listingu 2. Została ona
zrealizowana w JME w celu zobrazowania możliwości tej
technologii. Równie dobrze serwer oczekujący na połącze-
nia może być zaimplementowany na dowolnej maszynie ob-
sługującej gniazda TCP.
Listing 4. HttpServlet storna serwera http
public class DeliveryServlet extends HttpServlet
{
public void init ( ServletConig conig ) throws
ServletException {
super . init ( conig ) ;
...
}
public void doPost ( HttpServletRequest request ,
HttpServletResponse response )
throws ServletException , IOException
{
//odebranie wiadomosci od klienta i analiza jej
BufferedReader br = request . getReader () ;
String buf = br . readLine () ;
System . out . println ( buf ) ;
//operacje zwiazane z otrzymanymi danymi ...
//przygotowanie odpowiedzi do klienta i wysłanie jej
response . setContentType ( "text/html" ) ;
PrintWriter out = response . getWriter () ;
out . println ( "Odpowiedz serwera OK" ) ;
out . close () ;
}
...
TLS(SSL)
Transport Layer Security jest protokołem bezpieczeństwa,
który bazuje na starszym protokole Secure Socket Layer
(SSL).
Ze względu na brak w TCP mechanizmów ochrony prze-
syłanych danych wykorzystuje się TLS. Umiejscowiony jest
on pomiędzy warstwą TCP a warstwą aplikacji co zapew-
nia prostotę jego wykorzystania w programie. Umożliwia
szyfrowanie danych, potwierdzanie tożsamości serwera/
klienta, zapewnianie integralności przesyłanych komuni-
katów. W JME (MIDP 2.0) TLS realizuje się po niewielkich
modyfikacjach kodu (Rysunek 3).
Listing 5. Interfejs Serwera RMI
package pl.awa;
public interface RMIServer extends Remote {
//metoda dodaje uzytkownika
public User addUser ( String name , String password , Address
address )
throws RemoteException ;
//zwraca obiekt klasy Address
public Address getAddress ( String userName )
throws RemoteException ;
Bibliografia
• XML-RPC – zdalne wywoływanie procedur oparte na języku
XML http://www.xmlrpc.com .
• WMA – Wireless Messaging API zbiór klas i metod do ob-
sługi komunikacji SMS/MMS
http://java.sun.com/products/wma/index.jsp
• SIP – Session Initiation Protocol protokół inicjowania sesji
http://developers.sun.com/mobility/apis/articles/sip/
60
www.sdjournal.org
Software Developer’s Journal 6/2008
441663205.019.png 441663205.001.png 441663205.002.png 441663205.003.png 441663205.004.png
 
Java Microedition
HTTP
Hypertext Transfer Protocol może służyć jako nośnik infor-
macji między MIDletem a serwerem. Określa on formę żą-
dań klienta, które tworzymy między innymi za pomocą po-
leceń GET lub POST. Synchronicznie tworzone są odpo-
wiedzi na żądanie ( response ).
Ze względu na to że jest to protokół bezstanowy, nie
zachowuje informacji o poprzednich transakcjach stosu-
je się mechanizm cookies. W przypadku Java Microedition
można wykorzystać zapis do pliku w RMS lub systemie pli-
ków (FileConnection API) urządzenia aby zapamiętać stan
transakcji. Standardowo w konfiguracji CLDC wykorzystu-
je się metodę Connector.open z określeniem protokołu http:
// oraz podaniem adresu serwera. Obiekt typu HttpConnec-
tion utworzony w ten sposób posiada metodę setRequest-
Method określającą rodzaj żądania HttpConnection.POST lub
HttpConnection.GET . W przypadku wywołania POST można
zdefiniować nagłówek http poprzez metodę setRequestPro-
perty(„name”,”value”) jak to jest pokazane na przykłado-
wym Listingu 3.
Właściwa treść wiadomości do serwera jest przesyła-
na strumieniowo analogicznie jak w gniazdach. Kod odpo-
wiedzi serwera otrzymujemy za pomocą metod getRespon-
seCode , która zwraca statyczną wartość typu integer okre-
ślającą kod (zdefiniowaną w klasie HttpConnection ) lub ge-
tResponseMessage w przypadku gdy istotna jest treść od-
powiedzi.
Natomiast stronę serwera można zrealizować w dowol-
nej technologii obsługującej HTTP. W artykule zostanie po-
kazana implementacja za pomocą Java Servlet. Na Listn-
Listing 6. Klasy implementujące interfejs Serializacji
import de.enough.polish.io.Serializable;
public class User implements Serializable {
public String name ;
public Address address ;
public String password ;
}
import de.enough.polish.io.Externalizable;
public class Address implements Externalizable {
private String street ;
private String city ;
public Address () {
// wymagany konstruktor
}
public Address ( String street , String city ){
super () ;
this . street = new String ( street ) ;
this . city = new String ( city ) ;
}
public void read ( DataInputStream in ) throws IOException {
this . street = in . readUTF () ;
this . city = in . readUTF () ;
}
public void write ( DataOutputStream out ) throws
IOException {
out . writeUTF ( this . street ) ;
out . writeUTF ( this . city ) ;
}
}
Listing 10. Implementacja serwera RMI
import de.enough.polish.rmi.RemoteException;
import de.enough.polish.rmi.RemoteHttpServlet;
public class GameServerImpl
extends RemoteHttpServlet
implements GameServer
{
public User addUser ( String name , String password ,
Address address )
throws RemoteException {
//...
//utworzenie obiektu klasy User ktory bedzie zwrocony
przez metode
User user = new User () ;
user . name = name ;
user . password = password ;
user . address = address ;
//...
return user ;
}
public Address getAddress ( String userName ) throws
RemoteException {
Listing 7. Poprawne wywołanie metody RemoteClient.open
this . server = ( RMIServer ) RemoteClient . open (
"pl.awa.RMIServer" ,
"http://localhost:8080/awa/myservice" ) ;
Listing 8. Błędne wywołanie metody RemoteClient.open
String myInterfaceName = "pl.awa.RMIServer" ;
this . server = ( RMIServer ) RemoteClient . open (
myInterfaceName ,
"http://localhost:8080/awa/myservice" ) ;
//...
//wyszukiwanie uzytkownika po nazwie z bazy danych
String street = getStreetFromDB ( userName ) ;
String city = getCityFromDB ( userName ) ;
Address address = new Address ( street , city ) ;
//...
return address ;
}
}
Listing 9. Zdalne wywołanie metody serwera
//...
User user = this . server . addUser ( name , password , address ) ;
System . out . println ( "Name:" + user . name . toString ()) ;
//...
Software Developer’s Journal 6/2008
www.sdjournal.org
61
441663205.005.png 441663205.006.png
Inżynieria
oprogramowania
Connection
StreamConnectionNotifier
DatagramConnection
InputConnection
OutputConnection
StreamConnection
ServerSockedConnection
UDPDatagramConnection
ContentConnection (MIDP 1.0)
SockedConnection
HttpConnection (MIDP 1.0)
SecureConnection
Rysunek 1. Hierarchia interfejsów komunikacji w JME
gu 4 wykorzystany zostaje interfejs HttpServlet oraz im-
plementacja dwóch jego metod doGET oraz doPOST , które re-
alizują określone w nazwie żądania i generują odpowiedzi
do klienta. Aplikację serwerową można uruchomić na kon-
tenerze wspierającym serwety jak np. Apache Tomcat lub
JBoss. Odnośnie wykorzystania HTTPS dostępnego od
MIDP 2.0 to analogia użycia jest podobna jak w przypad-
ku TLS.
Cała idea opiera się na traktowaniu obiektów zdalnych
w ten sam sposób jak tych działających lokalnie. W konfi-
guracji CLDC JME standardowo nie można spotkać biblio-
teki odpowiedzialnej za obsługę RMI. Istnieje gotowe roz-
wiązanie opcjonalne J2MEPolish RMI, które jest dostęp-
ne w dwóch licencjach GPL oraz w komercyjnej Commer-
cial License.
Za pomocą tego narzędzia można w przyjemy i szybki
sposób zaimplementować mobilnego klienta komunikujące-
go się ze zdalnym serwerem. Wszystkie wywołania metod
RMI
Remote Method Invocation jest mechanizmem, który organizuje
komunikację między obiektami Java działającymi na różnych
maszynach wirtualnych w środowisku rozproszonym. Techni-
ka ta umożliwia zdalne wywołania metod (RPC) obiektów w ję-
zyku Java w przeźroczysty sposób dla programisty ukrywając
niskopoziomowe szczegóły związane z obsługą protokołów.
TCP
SocketConnection socketConnection =
(SocketConnection) Connection.open("socket://hostName:5000");
socketConnection.setSocketOption(SocketConnection.DELAY, 0);
OutputSteream os = socketConnection.openOutputStream());
Klient
Strumień danych lub
komunikaty aplikacji
Serwer
MIDIet
Serwer
TLS (SSL)
TCP
Pakiety
TCP
SecureConnection socketConnection =
(SecureConnection) Connector.open("ssl://hostName:5001");
String secureProtocolName =
secureConnection.getSecurityInfo().getProtocolName();
OutputSteream os = secureConnection.openOutputSteream();
IP
Pakiety IP
IP
Rysunek 2. Komunikacja poprzez gniazda TCP
Rysunek 3. Transformacja na gniazda bezpieczeństwa TLS
62
www.sdjournal.org
Software Developer’s Journal 6/2008
441663205.007.png 441663205.008.png 441663205.009.png 441663205.010.png 441663205.011.png 441663205.012.png 441663205.013.png 441663205.014.png 441663205.015.png
 
Zgłoś jeśli naruszono regulamin