2008 06 Java Microedition – metody integracji aplikacji [Inzynieria Oprogramowania]

background image

58

Inżynieria

oprogramowania

www.sdjournal.org

Software Developer’s Journal 6/2008

Java Microedition

– metody integracji aplikacji

A

plikacje Java Microedition (konfiguracji
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.

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.

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ó-

Albert Wachowicz

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

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)

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

()

;

}

}

background image

Java Microedition

59

www.sdjournal.org

Software Developer’s Journal 6/2008

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.

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:

• 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:

Listing 2.

Metoda nasłuchujące na TCP

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)

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

()

;

}

}

Listing 3.

Przykładowa metoda POST

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

()

;

}

}

background image

60

Inżynieria

oprogramowania

www.sdjournal.org

Software Developer’s Journal 6/2008

• JSON,
• Burlap,
• JINI,
• GASP,
• OpenDMTP,
• Payment API,
• Jsch.

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

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.

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.

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).

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/

Listing 4.

HttpServlet storna serwera http

public

class

DeliveryServlet

extends

HttpServlet

{

public

void

init

(

ServletConfig

config

)

throws

ServletException

{

super

.

init

(

config

)

;

...

}

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

()

;

}

...

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

;

background image

Java Microedition

61

www.sdjournal.org

Software Developer’s Journal 6/2008

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 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"

)

;

Listing 9.

Zdalne wywołanie metody serwera

//...

User

user

=

this

.

server

.

addUser

(

name

,

password

,

address

)

;

System

.

out

.

println

(

"Name:"

+

user

.

name

.

toString

())

;

//...

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

{

//...

//wyszukiwanie uzytkownika po nazwie z bazy danych

String

street

=

getStreetFromDB

(

userName

)

;

String

city

=

getCityFromDB

(

userName

)

;

Address

address

=

new

Address

(

street

,

city

)

;

//...

return

address

;

}

}

background image

62

Inżynieria

oprogramowania

www.sdjournal.org

Software Developer’s Journal 6/2008

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.

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.

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

Rysunek 1.

Hierarchia interfejsów komunikacji w JME

CLDC Generic Connection

Framework Interfaces

SockedConnection

HttpConnection (MIDP 1.0)

SecureConnection

MIDP

2.0

Interfaces

Connection

DatagramConnection

OutputConnection

InputConnection

StreamConnection

StreamConnectionNotifier

ServerSockedConnection

UDPDatagramConnection

ContentConnection (MIDP 1.0)

Rysunek 2.

Komunikacja poprzez gniazda TCP

Klient

Serwer

Serwer

MIDIet

TCP

TCP

IP

IP

Strumień danych lub

komunikaty aplikacji

Pakiety

Pakiety IP

Rysunek 3.

Transformacja na gniazda bezpieczeństwa TLS

TCP

TLS (SSL)

SocketConnection socketConnection =

(SocketConnection) Connection.open("socket://hostName:5000");

socketConnection.setSocketOption(SocketConnection.DELAY, 0);

OutputSteream os = socketConnection.openOutputStream());

SecureConnection socketConnection =

(SecureConnection) Connector.open("ssl://hostName:5001");

String secureProtocolName =

secureConnection.getSecurityInfo().getProtocolName();

OutputSteream os = secureConnection.openOutputSteream();

background image

63

Java Microedition

www.sdjournal.org

Software Developer’s Journal 6/2008

oraz dostępność obiektów dają wrażenie ich lokalnego wy-
stępowania po stronie klienta i vice versa. Aby to uzmysło-
wić drogiemu Czytelnikowi w dalszej części zostaną przed-
stawione kolejne kroki jakie należy podjąć aby to zrealizo-
wać.

Na pierwszym etapie definiujemy zdalny interfejs, który bę-

dzie wspólnym protokołem między klientem a serwerem. Okre-
śla się w nim metody, które będzie udostępniał serwer. Jak
można zauważyć na Listingu 5 wymagane jest aby dziedziczył
on po interfejsie

de.enough.polish.rmi.Remote

oraz każda me-

toda musi mieć możliwość zgłaszania wyjątku

de.enough.po-

lish.rmi.RemoteException

.

W kolejnym kroku należy zdefiniować zbiór klas, któ-

re będą wspólne dla obydwu stron. Klasy te muszą imple-
mentować interfejsy serializacji

de.enough.polish.io.Seria-

lizable

lub de.enough.polish.io.Externalizable. Serializacja

w najprostszym określeniu polega na procesie przekształ-
cenia obiektów do postaci strumienia bajtów. Dzięki zasto-
sowaniu tego mechanizmu w RMI można przesyłać obiek-
ty poprzez strumieniowy protokół sieciowy. W klasie imple-
mentującej Serializable programista nie musi martwić się
o proces serializacji dokonuje się on automatycznie jak to
widać na Listingu 6. Natomiast różnica w klasie implemen-
tującej

Externalizable

wynika z tego że należy zaimple-

Listing 11.

Przykładowy plik WSDL usługi Wheather

<

?xml version=

"1.0"

encoding=

"UTF-8"

?

>

<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI

2.1.2_01-hudson-189-. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is
JAX-WS RI 2.1.2_01-hudson-189-. -->

<

definitions xmlns:wsu=

"http://docs.oasis-open.org/wss/2004/01/oasis-

200401-wss-wssecurity-utility-1.0.xsd"

xmlns:wsp=

"http://schemas.xmlsoap.org/ws/2004/09/policy"

xmlns:

soap=

"http://schemas.xmlsoap.org/wsdl/soap/"

xmlns:tns=

"http://calculator.me.org/"

xmlns:xsd=

"http:

//www.w3.org/2001/XMLSchema"

xmlns=

"http://schemas.xmlsoap.org/wsdl/"

targetNamespace=

"http://

calculator.me.org/"

name=

"CalculatorWSService"

>

<

types

>

<

xsd:schema

>

<

xsd:import namespace=

"http://calculator.me.org/"

schemaLocation=

"http://localhost:8080/CalculatorApp/CalculatorWSService?xsd=

1"

><

/xsd:import

>

<

/xsd:schema

>

<

/types

>

<

message name=

"add"

>

<

part name=

"parameters"

element=

"tns:add"

><

/part

>

<

/message

>

<

message name=

"addResponse"

>

<

part name=

"parameters"

element=

"tns:addResponse"

><

/part

>

<

/message

>

<

portType name=

"CalculatorWS"

>

<

operation name=

"add"

>

<

input message=

"tns:add"

><

/input

>

<

output message=

"tns:addResponse"

><

/output

>

<

/operation

>

<

/portType

>

<

binding name=

"CalculatorWSPortBinding"

type=

"tns:CalculatorWS"

>

<

soap:binding transport=

"http://schemas.xmlsoap.org/soap/http"

style=

"document"

><

/soap:binding

>

<

operation name=

"add"

>

<

soap:operation soapAction=

""

><

/soap:operation

>

<

input

>

<

soap:body use=

"literal"

><

/soap:body

>

<

/input

>

<

output

>

<

soap:body use=

"literal"

><

/soap:body

>

<

/output

>

<

/operation

>

<

/binding

>

<

service name=

"CalculatorWSService"

>

<

port name=

"CalculatorWSPort"

binding=

"tns:CalculatorWSPortBinding"

>

<

soap:address location=

"http://localhost:8080/CalculatorApp/CalculatorWSService"

><

/soap:address

>

<

/port

>

<

/service

>

<

/definitions

>

background image

64

Inżynieria

oprogramowania

www.sdjournal.org

Software Developer’s Journal 6/2008

Listing 12.

Klasa pnia wygenerowany automatycznie

public

class

CalculatorWSService_Stub

implements

CalculatorWSService

,

javax

.

xml

.

rpc

.

Stub

{


private

String

[]

_propertyNames

;

private

Object

[]

_propertyValues

;


public

CalculatorWSService_Stub

()

{

_propertyNames

=

new

String

[]

{

ENDPOINT_ADDRESS_

PROPERTY

}

;

_propertyValues

=

new

Object

[]

{

"http://localhost:8080/

CalculatorApp/CalculatorWSService"

}

;

}


public

void

_setProperty

(

String

name

,

Object

value

)

{

int

size

=

_propertyNames

.

length

;

for

(

int

i

=

0

;

i

<

size

;

++

i

)

{

if

(

_propertyNames

[

i

]

.

equals

(

name

))

{

_propertyValues

[

i

]

=

value

;

return

;

}

}

String

[]

newPropNames

=

new

String

[

size

+

1

]

;

System

.

arraycopy

(

_propertyNames

, 0,

newPropNames

,

0,

size

)

;

_propertyNames

=

newPropNames

;

Object

[]

newPropValues

=

new

Object

[

size

+

1

]

;

System

.

arraycopy

(

_propertyValues

, 0,

newPropValues

,

0,

size

)

;

_propertyValues

=

newPropValues

;


_propertyNames

[

size

]

=

name

;

_propertyValues

[

size

]

=

value

;

}


public

Object

_getProperty

(

String

name

)

{

for

(

int

i

=

0

;

i

<

_propertyNames

.

length

;

++

i

)

{

if

(

_propertyNames

[

i

]

.

equals

(

name

))

{

return

_propertyValues

[

i

]

;

}

}

if

(

ENDPOINT_ADDRESS_PROPERTY

.

equals

(

name

)

||

USERNAME_PROPERTY

.

equals

(

name

)

||

PASSWORD_PROPERTY

.

equals

(

name

))

{

return

null

;

}

if

(

SESSION_MAINTAIN_PROPERTY

.

equals

(

name

))

{

return

new

Boolean

(

false

)

;

}

throw

new

JAXRPCException

(

"Stub does not recognize

property: "

+

name

)

;

}


protected

void

_prepOperation

(

Operation

op

)

{

for

(

int

i

=

0

;

i

<

_propertyNames

.

length

;

++

i

)

{

op

.

setProperty

(

_propertyNames

[

i

]

,

_propertyValu

es

[

i

]

.

toString

())

;

}

}


public

int

add

(

int

i

,

int

j

)

throws

java

.

rmi

.

RemoteException

{

Object

inputObject

[]

=

new

Object

[]

{

new

Integer

(

i

)

,

new

Integer

(

j

)

}

;


Operation

op

=

Operation

.

newInstance

(

_qname_operation_

add

,

_type_add

,

_type_addResponse

)

;

_prepOperation

(

op

)

;

op

.

setProperty

(

Operation

.

SOAPACTION_URI_PROPERTY

,

""

)

;

Object

resultObj

;

try

{

resultObj

=

op

.

invoke

(

inputObject

)

;

}

catch

(

JAXRPCException

e

)

{

Throwable

cause

=

e

.

getLinkedCause

()

;

if

(

cause

instanceof

java

.

rmi

.

RemoteException

)

{

throw

(

java

.

rmi

.

RemoteException

)

cause

;

}

throw

e

;

}


return

((

Integer

)((

Object

[])

resultObj

)[

0

])

.

intValue

()

;

}


protected

static

final

QName

_qname_operation_add

=

new

QName

(

"http://calculator.me.org/"

,

"add"

)

;

protected

static

final

QName

_qname_addResponse

=

new

QName

(

"http://calculator.me.org/"

,

"addResponse"

)

;

protected

static

final

QName

_qname_add

=

new

QName

(

"http://calculator.me.org/"

,

"add"

)

;

protected

static

final

Element

_type_addResponse

;

protected

static

final

Element

_type_add

;

static

{

_type_addResponse

=

new

Element

(

_qname_addResponse

,

_complexType

(

new

Element

[]

{

new

Element

(

new

QName

(

""

,

"return"

)

,

Type

.

INT

)})

, 1, 1,

false

)

;

_type_add

=

new

Element

(

_qname_add

,

_complexType

(

new

Element

[]

{

new

Element

(

new

QName

(

""

,

"i"

)

,

Type

.

INT

)

,

new

Element

(

new

QName

(

""

,

"j"

)

,

Type

.

INT

)})

, 1, 1,

false

)

;

}

private

static

ComplexType

_complexType

(

Element

[]

elements

)

{

ComplexType

result

=

new

ComplexType

()

;

result

.

elements

=

elements

;

return

result

;

}

}

background image

65

Java Microedition

www.sdjournal.org

Software Developer’s Journal 6/2008

mentować metody

read

i

write

, które odpowiednio czyta-

ją ze strumienia oraz zapisują do strumienia. Jeśli jednak
nie ma potrzeby tworzenia nowych klas, które będą nośni-
kiem informacji możemy wykorzystać standardowe klasy
Java Microedition takie jak np.

String

lub

Vector

. W zależ-

ności o skomplikowania zastosowania mogą one stanowić
elementy parametrów metod jak i być zwracane przez me-
tody serwera. Większość standardowych klas wspiera se-
rializację jednak występują pewne ograniczenia w niektó-
rych przypadkach.

Zalecane jest zapoznanie się przed ich zastosowaniem

w dokumentacji dostępnej na stronie J2MEPolish. Na tym

poziomie kończy się definiowanie wspólnej części interfej-
su wymiany między klientem a serwerem. W dalszej części
należy zdefiniować klasy, które będą wykorzystywały owy
interfejs po stronie klienta i serwera. W kliencie tworzy-
my połączenie z serwerem wykorzystując metodę

de.eno-

ugh.polish.rmi.RemoteClient.open()

. Listing 7 przedstawia

poprawne konstrukcję wywołania tej metody. Przyjmuje
ona pełną nazwę interfejsu, który zdefiniowaliśmy oraz ad-
res serwera wraz ze ścieżką do serwisu RMI. Należy pa-
miętać aby definiować te parametry bezpośrednio w wy-
wołaniu metody a nie przypisując je do zmiennych a na-
stępnie przekazywaniu ich do metody jak to jest pokaza-
ne na Listingu 8.

W przypadku sukcesu nawiązania połączenia z serwe-

rem poprzez powyższą metodę klient może wywoływać me-
tody serwera poprzez interfejs o nazwie (RMIServer). Wy-
korzystuje się do tego referencje obiektu, który zwróciła
metoda open jak to przedstawia Listing 9.

W odpowiedzi w tym przypadku zwracany jest obiekt

klasy z którym należy obchodzić się zupełnie w sposób
lokalny.

Ostatnim etapem konstruowania naszego mechanizmu

wykorzystującego RMI jest implementacja serwera. Klasa
serwera jest serwletem dziedziczącym po de.enough.po-
lish.rmi.RemoteHttpServlet
oraz implementująca jednocze-
śnie metody naszego wspólnego interfejsu o nazwie RMI-
Server (Listing 10). Jest to część wykonawcza całego me-
chanizmu i należy zadbać o poprawną konstrukcję zwra-
canych obiektów.

Proces kompilacji oraz budowania serwera wykra-

cza poza ramy tego artykułu, która prezentuje tylko za-
rys z poziomu języka Java. Jednak dla ułatwienia w kata-
logu {j2mepolish-dir}/samples/rmi znajduje się przykłado-

Listing 13.

Zdalny interfejs serwera

public

interface

CalculatorWSService

extends

java

.

rmi

.

Remote

{

public

int

add

(

int

i

,

int

j

)

throws

java

.

rmi

.

RemoteExc

eption

;

}

Listing 14.

Przykład wywołania metody serwera

public

Integer

getRemoteResult

(

int

x

,

int

y

){

Integer

result

=

null

;

try

{

//utworzenie obiektu reprezentujacego serwer

CalculatorWSService

webClient

=

new

CalculatorWSService_Stub

()

;

//wywolanie zdalnej metody

int

z

=

webClient

.

add

(

x

,

y

)

;


result

=

new

Integer

(

z

)

;

}

catch

(

Exception

ex

)

{

System

.

err

.

print

(

ex

)

;

}

return

result

;

}

Rysunek 4.

Web services podstawowe elementy i operacje

Serwer usług

Rejestr UDDI

3. Komunikacja SOAP

1. Rejestracja usługi - opis WSDL

2. Wyszukiwane usługi

W Sieci

http://developers.sun.com/mobility/allarticles/#networking
h t t p : / / d e v e l o p e r s . s u n . c o m / m o b i l i t y / m i d p / a r t i c l e s/

socketRMI/

http://www.j2mepolish.org/cms/leftsection/documentation/

rmirpc.html

http://kxmlrpc.objectweb.org
http://ksoap.objectweb.org/
ht tp : //w w w.netbeans .org /kb / 60 /mobilit y /mobile - dil-

bert.html

http://developers.sun.com/mobility/allarticles/#ws
http://developers.sun.com/mobility/allarticles/#wma
http://ksync.objectweb.org
http://developers.sun.com/mobility/midp/articles/syncml/
ht tp : //java .sun.com /developer/ Books /J2MEwireless/

J2ME12.pdf

http://developers.sun.com/mobility/midp/articles/jxme/
http://developers.sun.com/mobility/allarticles/#wma
http://tavon.org/work/JSON-J2ME
http://www.forum.nokia.com/main/resources/technologies/

java/documentation/networking.html

http://developer.sonyericsson.com/wiki/display/leftnav/

Java+Connectivity

http://developer.motorola.com/docstools/
http://developer.samsungmobile.com/Developer/index.jsp

background image

66

Inżynieria

oprogramowania

www.sdjournal.org

Software Developer’s Journal 6/2008

wy projekt gdzie został napisany skrypt w ANT budujący
jednocześnie aplikację klienta i serwer. Będzie on stano-
wił pomocą deskę dla początkujących programistów. Uwa-
gę należy zwrócić na proces obfuskacji dokonywany czę-
sto podczas budowania aplikacji. Podczas tego procesu
paczka jar wspólnych klas także zostaje poddana tej opty-
malizacji.

Należy pamiętać, że jeśli dokonano obfuskacji to pacz-

ka jar wspólnych klas musi się znaleźć po obu stronach
jednocześnie na kliencie jak i na serwerze. Pominięcie te-
go faktu jest sygnalizowane najczęściej wyjątkiem Class
not found: a
lub Class cast exception wynika to przede
wszystkim ze zmiany nazwy klas po zakończeniu pracy
obfuscatora.

Web Services SOAP

Simple Object Access Protocol jest standardem wymiany
informacji, którego składnia oparta jest na XML. Protokół
SOAP należy do grupy rozwiązań określanych terminem
Web Services.

Technologia Web Services zapewnia konstrukcję roz-

proszonych komponentów usługowych. W ramach Web
Services oprócz SOAP odpowiedzialnego za zdalne wy-
woływanie usługi, istnieje jeszcze WSDL oraz UDDI (Ry-
sunek 4).

Język opisu interfejsu WSDL (Web Services Descrip-

tion Language) służy do dystrybucji usług sieciowych nie-
zależnie od jej implementacji. UDDI (Universal Descrip-
tion, Discovery and Integration
) ułatwia udostępnianie do-
kumentów WSDL przez umieszczenie ich w specjalnej ba-
zie danych.

Zarejestrowane komponenty usług mogą być następnie

przeszukiwane przez klientów w celu ich wykorzystania.

Wracając do Java Microedition komunikację SOAP moż-

na zrealizować wykorzystując z jednej strony opcjonalną
paczkę JSR-172 lub dołączyć do aplikacji bibliotekę jar z
implementacją tego protokołu. Specyfikacja JSR-172 Web
Service jest uboższym zbiorem interfejsów pochodzącym
od JSE API JAX-RPC(1.1). Dostarcza infrastrukturę Web
Services bazująca na synchronicznym modelu zdalnych
wywołań procedur RPC.

Oferuje szeroką paletę typów danych oraz komunikację

poprzez wiele protokołów sieciowych między innymi popu-

larnego HTTP(S). W porównaniu do JSE wersja mobilna
jest poddana znacznym restrykcjom:

• nie wspiera asynchronicznych wiadomości;
• brak załączników w SOAP;
• wiadomości w reprezentacji literal (document/literal);
• brak wsparcia mapowania typów (brak paczki ja-

vax.xml.rpc.encoding);

• brak mechanizmu wyszukiwania UDDI.

Napisanie MIDletu zintegrowanego z serwerem za pomo-
cą SOAP dokonujemy od zlokalizowania adresu url usłu-
gi Web Service.

W artykule dla ułatwienia zostanie wykorzystany przy-

kładowy serwis Calculator pochodzący z pakietu NetBe-
ans 6.0 (menu File->New Project->Samples->Web Service-
>Calculator
).

Zostaje on uruchomiony na lokalnym serwerze także do-

łączonym do tego narzędzia. Zatem adres do pliku wsdl jest
następujący: http://localhost:8080/CalculatorApp/CalculatorW
SService?wsdl

Definicja pliku WSDL dla danego serwisu może wyglądać

tak jak to przedstawia Listing 11.

W dalszej kolejności przechodzimy do realizacji klienta w

którym należy zaimplementować:

• stub czyli pień czyli najprościej określając klasę przez

którą przechodzą wszystkie żądania i odpowiedzi z
serwera;

• interfejs serwisu;
• klasę uruchamiającą zdalną metodę Web Service.

Generowanie klasy pnia można dokonać automatycznie korzy-
stając z takich narzędzi jak Carbide.j lub Netbeans IDE 6.0,
WTK Sun 2.5. We wszystkich przypadkach po prostu należy
podać adres url do pliku WSDL Web Service jak jest to poka-
zane na Rysunku 5 .

Więcej informacji na temat tych narzędzi oraz wspo-

mnianego procesu znajduje się na stronach: http://www.j
2mepolish.org/cms/leftsection/documentation/rmirpc.html
, http://
kxmlrpc.objectweb.org.
W wyniku zautomatyzowanego działa-
nia tych narzędzi zostaje wygenerowana klasa pnia (Listing 12)
oraz zdalny interfejs serwera (Listing 13).

Utworzone w ten sposób klasy po prostu dołączamy do

naszej aplikacji. Przykładowe wywołanie metody serwera
przy zastosowaniu wygenerowanych klas przedstawia Li-
sting 14.

Jak można zaobserwować proces tworzenia klienta oka-

zał się w większości automatyczny. Cała technika tworzenia
jest przeźroczysta dla programisty. Wygenerowane klasy są
bezpośrednio napisane w Java ukrywając szczegóły imple-
mentacyjne SOAP.

Podsumowanie

Aby ułatwić Czytelnikowi wybór właściwej metody do swoje-
go zastosowania zostanie przedstawione krótkie zestawienie
mocnych i słabych stron opisanych metod.

Gniazda są szybkim rozwiązaniem w przypadku pro-

stych wiadomości nie wymagające definiowania rozbudo-
wanego protokołu. Dostępne są na każdym urządzeniu od

Rysunek 5.

Carbide.j oraz NeatBeans IDE 6.0 generowanie

pnia


Wyszukiwarka

Podobne podstrony:
2008 Metody komputerowe dla inzynierow 20 D 2008 1 8 22 18 59id 26588 ppt
2008 Metody komputerowe dla inzynierow 18 D 2008 1 8 22 16 21id 26586 ppt
Inzynieria oprogramowania w ujeciu obiektowym UML wzorce projektowe i Java iowuje
Metodyka Integrowanej Ochrony PORZECZKI
Metodyka Integrowanej Ochrony MALINY PRODUCENT
2006 06 Wstęp do Scrum [Inzynieria Oprogramowania]
2008 06 Test CAPTCHA
PiKI 2008 06
Metodyka integrowanej ochrony pieczarki
2008 06 pisemny klucz
metody, Integracyjne, Integracyjne
2008 06 pisemny
mat fiz 2008 06 02
Metodyka Integrowanej Ochrony TRUSKAWKI PRODUCENT
2008 06 05 WHR B DAinstrukcja
2008 06 Edytor grafiki wektorowej Inkscape [Grafika]

więcej podobnych podstron