Wpis ten dedykuję Profesorowi Ryszardowi K., który potrafi obrzydzić jave prawie każdemu.

Applety to zuo

Jest to prawda objawiona, która rozwinęła się w udowodnioną. Dziękować za to można różnym mało rzetelnym osobom, które propagowały też np. atak na kompa przez coockie. Niestety nie zmienia to faktu, że applety są raczej technologią odchodzącą powoli do lamusa. Pytanie co w zamian? Niewątpliwie największą grupę zamienników dla appletów stanową wszelkiej maści animacje flash. Posiadają one ogromne możliwości i dzięki prostocie tworzenia nie wymagają zbyt dużo wiedzy. Z drugiej strony trzeba mieć smykałkę do grafiki. Flash sprawdza się, moim zdaniem, słabo jeśli chodzi o obróbkę danych i pracę z aplikacjami webowymi. No właśnie drugą grupę stanową aplikacje działające po stronie serwera, których interfejs to strona www. Jest to całkiem dobre rozwiązanie ponieważ nie wymaga dużych nakładów pracy ze strony programistów jeśli chodzi o tworzenie GUI. Bierze się webmastera przez jeden dzień szkoli w zakresie wybranej technologii np. Velocity lub Wicket i gotowe. Można też pójść po najmniejszej linii oporu i napisać GUI w GWT.

Ok, jest web, ale są aplikacje, które wymagają okienkowych „bajerów” np. dynamicznych wykresów, a jednocześnie nie chcemy tego robić we flashu. Co ze starszymi programami w javie, które ktoś chce migrować na serwer. Tu pojawia się bohater dzisiejszego wieczora.

Java Network Launching Protocol (jnlp)

Jest to jedna z mało znanych ciekawostek javy. Obecnie coraz popularniejsza i coraz częściej stosowana. Jednak po kolei.

Stwórzmy projekt w mavenie i zmieńmy kompilator na jave 5. Następnie klasa główna programu niech będzie wyglądać w następujący sposób:

Listing 1. Główna klasa programu

<br></br><span class="keywordStyle">package</span> <span class="packageNameStyle">eu.runelord.blog</span>;<br></br><br></br><span class="keywordStyle">import</span> <span class="importNameStyle">java.awt.Dimension</span>;<br></br><br></br><span class="keywordStyle">import</span> <span class="importNameStyle">javax.swing.JFrame</span>;<br></br><br></br><span class="javadocCommentStyle">/**<br></br> * Hello world!<br></br> * <br></br> */</span><br></br><span class="keywordStyle">public</span> <span class="keywordStyle">class</span> <span class="nonPrimitiveTypeStyle">App</span> {<br></br><span class="keywordStyle">public</span> <span class="keywordStyle">static</span> <span class="primitiveTypeStyle">void</span> <span class="methodStyle">main</span>(<span class="nonPrimitiveTypeStyle">String</span>[] <span class="variableStyle">args</span>) {<br></br><span class="nonPrimitiveTypeStyle">JFrame</span> <span class="variableStyle">frame</span> = <span class="primitiveLiteralStyle">null</span>;<br></br><span class="keywordStyle">if</span> (<span class="variableStyle">args</span> != <span class="primitiveLiteralStyle">null</span> && <span class="variableStyle">args.length</span> > <span class="numericalLiteralStyle">0</span>)<br></br><span class="variableStyle">frame</span> = <span class="keywordStyle">new</span> <span class="constructorStyle">JFrame</span>(<span class="variableStyle">args</span>[<span class="numericalLiteralStyle">0</span>]);<br></br><span class="keywordStyle">else</span><br></br><span class="variableStyle">frame</span> = <span class="keywordStyle">new</span> <span class="constructorStyle">JFrame</span>(<span class="doubleQuoteStyle">"Error!"</span>);<br></br><span class="methodStyle">frame.setDefaultCloseOperation</span>(<span class="constantStyle">JFrame.EXIT_ON_CLOSE</span>);<br></br><br></br><span class="methodStyle">frame.setPreferredSize</span>(<span class="keywordStyle">new</span> <span class="constructorStyle">Dimension</span>(<span class="numericalLiteralStyle">350</span>, <span class="numericalLiteralStyle">50</span>));<br></br><span class="methodStyle">frame.setSize</span>(<span class="keywordStyle">new</span> <span class="constructorStyle">Dimension</span>(<span class="numericalLiteralStyle">350</span>, <span class="numericalLiteralStyle">50</span>));<br></br><span class="methodStyle">frame.setVisible</span>(<span class="primitiveLiteralStyle">true</span>);<br></br><br></br>    }<br></br>}<br></br>

Tyle nam do szczęścia wystarczy.

Konfiguracja serwera

Zaletą jnlp jest możliwość uruchomienia programu javowego na praktycznie „gołym” serwerze www np. Apache. By to uczynić trzeba, poza wrzuceniem plików, ale to za chwilę, dodać pliki .jnlp i .jardiff do pliku .htaccess:

Listing 2. Treść pliku .htaccess

<br></br>AddType application/x-java-jnlp-file    .jnlp<br></br>AddType application/x-java-archive-diff .jardiff<br></br>

plik ten będzie trzeba wrzucić na serwer. Jeżeli mamy możliwość warto te ustawienia dodać do httpd.conf jednak zazwyczaj administratorzy bezpłatnych serwerów nie dają się przekonać do odpowiednich zmian. Tyle jeśli chodzi o konfigurację. Jedziem dalej

Deskryptor web.jnlp

W najprostszym opisie jnlp działa w następujący sposób:

  • Pobieramy plik jnlp
  • Java rozpoznaje go jako swój i uruchamia mechanizm Java Web Start (jws)
  • Ściągają się pliki jar i są weryfikowane
  • Wywoływana jest metoda main

Od razu kilka pytań. Skąd jws wie gdzie leżą jary? Skąd JVM wie która to klasa główna? Po co podpisywać jara? Odpowiedź na ostatnie pytanie jest banalna, jar podpisany i zweryfikowany przez klienta jest bezpieczny. Z pozostałymi dwoma pytaniami sprawa ma się troszkę inaczej. Plik jnlp służy do przekazania podstawowych informacji o tym gdzie szukać pliku jar z programem i jak go uruchomić. Przykładowy plik web.jnlp:

Listing 3. web.jnlp czyli deskryptor jws

<?xml version="1.0" encoding="utf-8"?><br></br><jnlp spec="1.0+" codebase="http://www.koziolekweb.yoyo.pl/examp/jnlp/"<br></br> href="web.jnlp"><br></br> <information><br></br>  <title>WebStart Demo</title><br></br>  <vendor>Bartek Kuczynski</vendor><br></br>  <homepage href="http://runelord.eu" /><br></br>  <description>A Java Webstart test</description><br></br>  <offline-allowed /><br></br> </information><br></br> <resources><br></br>  <j2se version="1.4+" /><br></br>  <jar href="JnlpForFUW-0.1.jar" /><br></br> </resources><br></br> <security><br></br>  <all-permissions /><br></br> </security><br></br> <application-desc main-class="eu.runelord.blog.App"><br></br>  <argument>Witaj przebrzydły świecie</argument><br></br> </application-desc><br></br></jnlp>

W pliku tym są zawarte informacje na temat wydawcy programu, wymaganej wersji javy oraz klasy głównej programu. Po co to ostatnie skoro można przeczytać manifest no bo tak. Nie jest to element obowiązkowy, ale nie zaszkodzi go dodać.Istnieje też możliwość przekazania parametrów do programu. Na zakończenie naszych dzisiejszych zmagań trzeba jeszcze plik jar podpisać i umieścić na serwerze. Przykładowa aplikację znajdziecie tutaj. Dokumentację jws można znaleźć tutaj dotyczy ona co prawda wersji 1.4.2, ale zawsze można pokopać za 1.6 😉 Oczywiście dokumentacja jest też w standardowym pakiecie dokumentacji javy.

Wspomnę jeszcze tylko o pracy z mavenem. Istnieją dwa pluginy pozwalające na pracę z jws. Pierwszy maven-webstart-plugin działa z mavenem1.x i można go olać. Drugi mojo-webstart-plugin pochłonął mi dwa wieczory i nadal nie chce działać. Narazie to olewam.