wtorek, 2 grudnia 2008

Klient web service w Java Micro Edition bez JSR-172

Przez ostatnie dwa dni walczyłem żeby podłączyć klienta web service w mojej aplikacji mobilnej. Na emulatorze wszystko śmigało aż miło ale testy na telefonie komórkowym nie powiodły się ponieważ moje telefony (SE K750i oraz Nokia 9300i) nie obsługują J2ME Web Services Specification (JSR-172), a kod generowanego klienta przez NetBeans właśnie na tej specyfikacji się opierał. To ogranicza liczbę urządzeń na których moja aplikacja będzie mogła działać.
Rozwiązania w mojej głowie pojawiły się dwa: albo zignorować i opierać wszystko na tej implementacji, albo ręcznie bawić się w parsowanie komunikatów SOAP (o zgrozo!).
Co prawda drugie rozwiązanie nie byłoby aż tak tragiczne ponieważ udało mi się znaleźć jakąś pomocną bibliotekę (kSOAP) no ale i tak nie jest tak fajnie jak powinno. Pozostając tymczasowo przy pierwszym (łatwo później podmienić takiego klienta) postanowiłem przepytać ludzi na pl.comp.lang.java czy nie mają jakiś pomysłów. Ostatecznie skontaktowałem się z Karolem Harezlakiem który podał mi rozwiązanie tego problemu.
Aby klient J2ME nie korzystał z JSR-172 należy użyć serwera proxy który będzie tłumaczył dane z web service na dane binarne których przetwarzaniem zajmie się już klient J2ME. Wszystko oczywiście łatwe i proste dzięki środowisku NetBeans IDE :)
Przejdźmy do praktycznych rzeczy:)

Web Service
Niech nasza usługa będzie super zaawansowaną usługą sieciową i niech jej zadaniem będzie mnożenie dwóch liczb :)
No to do roboty, tworzymy projekt new project -> Java EE -> EJB Module. Nazwa: MultiplyingService, w następnym oknie wybieramy serwer aplikacji na którym będzemy uruchamiać usługę, ja wybrałem GlassFisha V2 (instaluje się razem z NetBeans). Koniecznie wybieramy wersje Java EE 5.
Żeby wszystkiego nie generować i przy okazji liznąć trochę EJB napiszemy sami usługę.
Dodajemy nowa klasę javy do projektu o nazwie: MultiplyingWS.java
package com.blogspot.wookasz.j2mecwsclient;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless
@WebService
public class MultiplyingWS {
public int multiply(int a, int b) {
return a * b;
}
}
Adnotacja Stateless oznacza, że mamy do czynienia z bezstanowym komponentem sesyjnym, który wzbogacony o adnotację WebService stanie się usługą sieciową zdolną do komunikacji poprzez protokół SOAP. Generacją WSDLa i innymi szczegółami zajmuje się serwer aplikacji.
Wykonujemy deploy na serwer.

Servlet
Ok, teraz musimy stworzyć servlet który będzie jednoczenie klientem usługi oraz będzie udostępniał jego wyniki klientowi J2ME.
Tworzymy nowy projekt ProxyServlet: New project -> Java Web -> Web Application. Dodajemy do niego New File -> Web Services -> Web Service Client. Usługę dla niego wybieramy z poprzednio utworzonego projektu.

Wykonujemy deploy na serwer.

J2ME Client
No to został nasz ostatni docelowy klocek. Tworzymy nową aplikację J2ME New Project -> J2ME -> Mobile Application o nazwie WSClient, wybierająć CLDC 1.1 oraz MIDP 2.0.
Do projektu dodajemy New File -> MIDP -> Java ME Client to Web Application. I konfigurujemy go jak na obrazkach:



Klikamy finish i zostanie dodany po chwili do projektu plik o nazwie MultiplyWSClient.java który jest naszym docelowym klientem usługi sieciowej. Jeszcze utwórzmy głowny MIDlet WSClient.java:
package com.blogspot.wookasz.j2mewsclient;

import java.io.IOException;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.*;

public class WSClient extends MIDlet implements CommandListener {
public void startApp() {
try {
Form form = new Form("WebService Client");
int res = new MultiplyWSClient().multiply(2, 2);
String text = "2 * 2 = " + res;
form.append(text);
Command exitCmd = new Command("Wyjscie", Command.EXIT, 0);
form.addCommand(exitCmd);
form.setCommandListener(this);
Display display = Display.getDisplay(this);
display.setCurrent(form);

} catch (IOException ex) {
ex.printStackTrace();
}
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

public void commandAction(Command c, Displayable d) {
notifyDestroyed();
}
}
I koniec! Jeśli wszystko wykonaliśmy poprawnie powinniśmy po odpaleniu emulatora otrzymać taki wynik:
Wszystko działa:) Testy na komórkach bez obsługi JSR-172 także wypadły pomyślnie!
Dziękuje bardzo Karolowi za pomoc!!

ps. dodam jeszcze, że całość została napisana na podstawie tutoriala: End-to-End Web Service Tutorial: Mobile Dilbert Application.

Brak komentarzy:

Prześlij komentarz