J2ME v kostce – jak se připojit k serveru

J2ME v kostce – jak se připojit k serveru

0

I když lokální javové aplikace výrazně rozšiřují možnosti mobilního telefonu, mnohem zajímavější mohou být aplikace s připojením k serveru, ať už pro přístup k aktuálním firemním datům, komunikaci se známými pomocí ICQ klienta nebo „mobilní“ správu serveru s použitím ssh klienta. Jak se z telefonu dostat na síť se naučíte v tomto článku.

Síťové možnosti J2ME

Rovnou vám prozradím, že zatím nejsou příliš velké. Výrobci telefonů jsou povinni implementovat pouze HTTP spojení. Navíc jsou ještě rozdíly v tom, kolik spojení může být otevřeno zároveň, nejlépe je počítat rovnou pouze s jedním (Nokia), nepíšete-li aplikaci speciálně pro jedno konkrétní zařízení, které více souběžných připojení podporuje.

Údajným důvodem, proč je vyžadováno pouze HTTP spojení, je to, že některé mobilní sítě jsou implementovány způsobem, který by se těžko přizpůsoboval připojení přes sokety, kdežto u HTTP spojení je celkem jedno, jaké jsou nižší vrstvy sítě. Z vlastní zkušenosti mohu říct, že některé telefony sokety podporují (např. od firmy Siemens či Motorola) a minimálně u T-mobile fungují.

Ve specifikaci MIDP-2.0 jsou sice oproti současnému MIDP-1.0 přidána navíc některá nízkoúrovňová rozhraní, například na již zmiňované sokety či dokonce UDP datagram, ale telefony tyto typy připojení nemusí podporovat. Ani nová specifikace nám pak příliš nepomůže a aplikace psané obecně pro všechny telefony si budou muset vystačit s HTTP protokolem, který má poněkud nepraktickou vlastnost, že vylučuje iniciaci spojení ze serveru.

HttpConnection

Třídy a rozhraní potřebné pro síťové připojení obsahuje balík javax.microedition.io. Než přejdu ke konkrétnímu příkladu, je potřeba si ještě něco říci o nejdůležitějším rozhraní, které budeme používat, a to HttpConnection.

HTTP protokol má formu požadavek-odpověď a všechny parametry musí být nastaveny dříve, než je požadavek odeslán. Od toho se odvíjí stavy, ve kterých se HTTP spojení může nacházet:

  • Nastavení (Setup) – spojení ještě není navázáno
  • Připojeno (Connected) – parametry byly odeslány, čeká se na odpověď
  • Zavřeno (Closed) – při volání metod je vyhozena IOException

Následující metody mohou být volány pouze ve fázi nastavení:

  • setRequestMethod
  • setRequestProperty

Do připojeného stavu přejde HTTP spojení zavoláním některé z metod, které vyžadují komunikaci se serverem:

  • openInputStream
  • openOutputStream
  • openDataInputStream
  • openDataOutputStream
  • getLength
  • getType
  • getEncoding
  • getHeaderField
  • getResponseCode
  • getResponseMessage
  • getHeaderFieldInt
  • getHeaderFieldDate
  • getExpiration
  • getDate
  • getLastModified
  • getHeaderField
  • getHeaderFieldKey

Příklad

Dnešní příklad neobsahuje žádnou zábavnou pointu, prostě se jen připojí k URL, které načte z atributu v JAD souboru, a ve formuláři zobrazí jeho obsah. Skládá se ze dvou tříd: TestHttpMIDlet coby základní třídy midletu a TestHttp pro načtení URL.

Připojení k serveru

import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
/**
 * Tato třída slouží pro komunikaci se serverem pomocí
 * HTTP spojení.
 */

public class TestHttp {
    /**
     * Metoda connect načte dané URL a vrátí jako String.
     * @param url URL které se má načíst
     * @return String Obsah daného URL
     * @throws IOException – Nemůže-li být spojení vytvořeno nebo
     * nastane-li jiná I/O chyba
     */

    public static String connect(String url)
        throws IOException {
        HttpConnection c = null;
        InputStream is = null;
        try {
            // Vytvoření HTTP připojení
            c = (HttpConnection) Connector.open(url);
            // Nastavení přístupové metody
            c.setRequestMethod(HttpConnection.GET);
            // Otevření vstupního proudu – po zavolání této metody
            // se HttpConnection nachází v připojeném stavu
            is = c.openInputStream();
            String s = null;
            // Zjištění délky přijatých dat
            int len = (int) c.getLength();
            if (len > 0) {
                // Délka dat je předem známá
                byte[] data = new byte[len];
                int actual = is.read(data);
                s = new String(data);
            } else {
                // Délka dat není předem známá
                StringBuffer buf = new StringBuffer();
                int ch;
                while ((ch = is.read()) != -1) {
                    buf.append((char) ch);
                }
                s = buf.toString();
            }
            return s;

        // I když nastane nějaká výjimka, je potřeba zavřít
        // InputStream a HttpConnection, proto se tyto příkazy
        // dají do finally bloku, který se provede vždy.
        } finally {
            if (is != null) {
                is.close();
            }
            if (c != null) {
                c.close();
            }
        }
    }
}

Midlet

Komunikace se serverem je časově velmi náročná záležitost, aby proto neblokovala uživatelské prostředí, je potřeba ji provést v jiném než hlavním vlákně.

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

/**
 * Jednoduchý midlet, který načte z JAD souboru parametr url,
 * pak se na dané URL připojí a načtená data zobrazí na displeji
 */

public class TestHttpMIDlet
   extends MIDlet
   implements CommandListener, Runnable {
   private Form loading;
   private Form form;
   private Command exit;
   private Display display;
   private String url;

   /**
    * Konstruktor třídy – vytvoří formulář
    */

   public TestHttpMIDlet() {
      form = new Form(„TestHttp“);
      exit = new Command(„Konec“, Command.BACK, 1);
      form.addCommand(exit);
      form.setCommandListener(this);
      loading = new Form(„“);
      loading.append(„Nahrávám…“);
      loading.setTicker(new Ticker(„Pracuju“));
      url = getAppProperty(„url“);
   }

   /**
    * Tuto metodu volá aplikační manažer při přechodu midletu
    * do aktivního stavu.
    */

   protected void startApp()
      throws MIDletStateChangeException {
      if (display == null) {
         display = Display.getDisplay(this);
      }
      display.setCurrent(loading);
      Thread t = new Thread(this);
      // Spuštění druhého vlákna, ve kterém probíhá
      // připojení k serveru
      t.start();
   }

   /**
    * Tuto metodu volá aplikační manažer při přechodu midletu
    * do pasivního stavu
    */
   protected void pauseApp() {
      // Jelikož odkaz na druhé vlákno není globální,
      // není zde potřeba nic dělat
   }

   /**
    * Tuto metodu volá aplikační manažer při ukončení aplikace
    */

   protected void destroyApp(boolean unconditional)
      throws MIDletStateChangeException {
   }

   /**
    * Metoda rozhraní CommandListener
    */

   public void commandAction(Command c, Displayable d) {
      if (c.equals(exit)) {
         try {
            destroyApp(true);
            notifyDestroyed();
         } catch (Exception e) {
         }
      }
   }

   /**
    * Metoda rozhraní Runnable na načtení URL a zobrazení
    * ve formuláři – provádí ji druhé vlákno
    */

   public void run() {
      String s;
      try {
         s = TestHttp.connect(url);
      } catch (Exception e) {
         s = e.getMessage();
      }
      form.append(s);
      display.setCurrent(form);
   }
}

Literatura a odkazy

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět