Pokazywanie postów oznaczonych etykietą applet. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą applet. Pokaż wszystkie posty

poniedziałek, 25 stycznia 2016

IceBoar, czyli jak radzić sobie lepiej z technologią Web Start

W poprzednim wpisie opowiedziałem o kłopotach na jakie możemy natrafić korzystając z technologi Java Web Start. Przede wszystkim nie mamy pewności na jakiej wersji Wirtualnej Maszyny Javy użytkownik uruchomi naszą aplikację. Musimy również podpisywać nasze aplikacje i działają one w piaskownicy web starta (proces javaws lub jp2launcher). Ale oto przedstawiam rozwiązanie części z tych problemów:



IceBoar to mój pierwszy projekt Open Source, który wylądował w repozytorium maven central. Dodatkowo był on finansowany i pisany na zlecenie Roche, więc mamy połączenie przyjemnego z pożytecznym.

Co robi IceBoar? Najłatwiej wyjaśnia to poniższy diagram ze strony projektu.



Gdy użytkownik kliknie linka na stronie www, ściągany jest plik JNLP. Zamiast uruchamiać od razu docelową aplikację, uruchamia on Ice Boar’a. Ten najpierw ściąga spakowaną Wirtualną Maszynę Javy (musimy ją wcześniej sami przygotować i udostępnić do ściągnięcia). Następnie rozpakowuje ją (ale nie instaluje w systemie), ściąga docelową aplikację wraz z zależnościami i uruchamia ją. Aplikacja jest już uruchamiana po za procesem web start’a (javaws / jp2launcher), więc IceBoar może zakończyć swoje działanie.

Podoba się? Mam nadzieję, że tak!

Dodatkowo zaimplementowałem mechanizm cache’owania ściąganej JVM’ki i rozpakowanej JVM’ki. Dzięki temu kolejne uruchomienie nie będzie musiało ponownie pobierać tego pliku. Będzie to tak długo działać, dopóki ktoś nie wyczyści katalogu temp.

Pobierane JAR’y są chache’owne z automatu przez mechanizm czystego web start’a, więc nie trzeba było tego implementować. Co prawda w logu wypisuje się, że je pobiera, ale tak na prawdę są one brane z cache’a web starta. Wystarczy porównać czasy pierwszego i drugiego uruchomienia.

Jak zacząć przygodę z IceBoar’em? Sugeruję przyjrzeć się przykładowemu projektowi: ice-boar-demo. Nie korzysta on co prawda z Webstart Maven Plugin’a i setup jest trochę czasochłonny (patrz Readme), ale prezentuje dokładnie to co potrzeba. Może kiedyś zrobię przykładowy projekt ze wspomnianym Maven’owym plugin’em. Kwestia tylko gdzie i czy można udostępniać spakowane JRE?

Tak więc zachęcam do przeglądania kodu, testowania, zgłaszania błędów, Pull Request’ów i dzielenia się feedbackiem. Wszystko jest mile widziane.

sobota, 26 grudnia 2015

Technologia Java Web Start - co i jak?

TL;DR Jeśli nie korzystałeś nigdy z technologi Java Web Start (pliki JNLP) i jeśli nie musisz tego robić, to spokojnie możesz nie czytać dalej - nie obrażę się. Jest to zamierająca technologia i niedługo nie będzie wspierana w nowszych przeglądarkach (zobacz: The Final Countdown for NPAPI). Jeśli jednak korzystałeś / musisz skorzystać z tej technologi, to pewnie [mam nadzieję] dowiesz się czegoś ciekawego z tego i kolejnych artykułów.

Czym jest Java Web Start? Popatrzmy na dokumentację Javy SE.


Powinniście kojarzyć powyższy widok. Zazwyczaj korzystamy z Java SE API, natomiast Web Start jest zdefiniowany trochę wyżej po lewej, zaraz koło Applet'ów - a to nie wróży nic dobrego.


Java Web Start pozwala nam na uruchamianie javowych aplikacji standalone, bezpośrednio po kliknięciu na link’a na stronie www. Nie jest potrzebna żadna instalacja. Jest to wygodny sposób na dystrybuowanie wśród użytkowników najnowszej wersji naszego oprogramowania standalone - wejdźcie na stronę X, kliknijcie link Y i uruchomi się najnowsza wersja oprogramowania z którego [niestety] musicie korzystać. Jest to coś innego niż aplety, bo aplikacja uruchamia się po za przeglądarką.

Jak to działa? Po kliknięciu na link ściągany jest plik JNLP, który jest on w formacie XML’owym. Generalnie plik ten zawiera informację,  co ma uruchomić, skąd pobrać JAR’y, parametry uruchomieniowe itd. Aby całość zadziałała, musimy mieć jakąś Javę zainstalowaną na docelowej maszynie klienckiej.

Tyle teorii. Moim zdaniem, ta technologia świetnie sprawdza się z tutorialem do Swinga, gdzie za pomocą jednokliku możemy odpalić przykład ze strony i zobaczyć efekt. Wystarczy kliknąć na poniższą ikonkę:

https://docs.oracle.com/javase/tutorialJWS/samples/uiswing/CelsiusConverterProject/CelsiusConverter.jnlp



I to by było na tyle. Jeśli chodzi o jakieś bardziej skomplikowane aplikacje, to już może nie być tak różowo. Oracle nigdy jakoś szczególnie nie dbał o jakość tej technologii, czasem wprowadzał niekompatybilne zmiany, zaostrzał security itd.

Największą jednak bolączką programistów zmuszonych do korzystania z tej technologi jest niepewność, na której wersji wirtualnej maszyny Javy będzie odpalona aplikacja. Póki jest to proste demo (tutorial do Swinga), to żadnych problemów nie powinno być. Gdy jednak stworzyliśmy kolosa, który z jakiś powodów działa tylko na konkretnej wersji JVM’a, to zaczynają się schody.

Gdy zdefiniujemy w naszym pliku JNLP, że aplikacja ma się odpalić na Javie 1.7, a user będzie miał zainstalowaną Javę 1.8, to może zobaczyć poniższy komunikat:


Ten i inne screeny otrzymałem grzebiąc w plikach JNLP edytora UML’a: ArgoUML, udostępniającego link do uruchomienia za pomocą Web Start'a.

Czyli aplikacja w tym wypadku uruchomi się na Javie 1.8. W przypadku, gdy mamy w systemie zainstalowane kilka wersji Javy, to użytkownik będzie miał możliwość wyboru, na której się uruchomi.

Jeszcze innym problemem, może być posiadanie przez użytkownika starszej wersji Javy. Jeśli zdefiniujemy, że aplikacja ma się tylko odpalać na wersji 1.8.0_50, a będziemy mieć zainstalowaną starszą (1.8.0_28), to dalej nie mamy pewności, na której się uruchomi - patrz komunikat poniżej.


Jak dobrze pamiętam, to jeszcze jest możliwość, że Web Start będzie próbował ściągnąć nowszą wersję JRE i zainstalować. Jest to spory problem w dużych firmach, gdzie korpo ludki mogą nie mieć (albo raczej nie powinni mieć) uprawnień do instalowania nowych rzeczy na swojej maszynie.

Inną niedogodnością jest jeszcze konieczność podpisywania swoich aplikacji. Od którejś wersji Javy, własne certyfikaty (self signed) są z domysłu blokowane. Trzeba więc albo zdobyć porządny certyfikat od zaufanego wystawcy (czytaj zapłacić), albo skonfigurować userom maszyny tak, aby mogli otwierać aplikacje z zaufanych źródeł.

Jak widać jest sporo tej babraniny, aby całość doprowadzić do ładu i składu. Spójrzmy zatem na kolejne fragmenty przykładowego pliku JNLP. Pozwoliłem sobie bazować na pliku z ArgoUML, ale dorzuciłem też parę ciekawych rzeczy, których tam nie ma zdefiniowanych.
<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for launching ArgoUML with WebStart -->
<jnlp
  spec="1.0+"
  codebase="http://argouml-downloads.tigris.org/maven2"
  href="http://argouml-downloads.tigris.org/jws/argouml-latest-stable.jnlp">

Całość będzie zawierać się w tagu jnlp. Możemy w nim zdefiniować atrybut codebase, który będzie naszym bazowym URL’em przy pobieraniu JAR’ów.

Bardzo ciekawy jest atrybut href. Jeśli jest on zdefiniowany, to po uruchomieniu pobranego pliku JNLP (czy to w przeglądarce, czy bezpośrednio z dysku), to Web Start pobierze ten plik jeszcze raz ze zdefiniowanego tutaj adresu i jego będzie interpretował! Jeśli wprowadzimy jakieś zmiany lokalnie w pliku JNLP, ale będzie istniał atrybut href, to nic nam to nie da! Dla celów produkcyjnych warto ustawić ten parametr, na pewno utrudni on życie początkujących hackerom.
<information>
    <title>ArgoUML Latest Stable Release 0.34</title>
    <vendor>Tigris.org (Open Source)</vendor>
    <homepage href="http://argouml.tigris.org/"/>
    <description>ArgoUML application.
                 This is the latest stable release.
    </description>
    <description kind="short">ArgoUML 0.34</description>
    <icon href="http://argouml.tigris.org/images/argologo16x16.gif" width="16" height="16" />
    <icon href="http://argouml.tigris.org/images/argologo32x32.gif" width="32" height="32" />
    <icon href="http://argouml.tigris.org/images/argologo64x64.gif" width="64" height="64" />
    <offline-allowed/>
  </information>

Dalej mamy definicje, które są gdzieś tam wyświetlane podczas uruchamiania aplikacji, czyli tytuł, wydawca, strona domowa, opis, ikonka itp. Ostanie ustawienie (offline-allowed) definiuje nam, że docelowa aplikacja może działać, gdy nie mamy połączenia z netem. Jest jeszcze możliwość tworzenia skrótu na pulpicie, menu start i inne pierdoły.
  <security>
    <all-permissions/>
  </security>
Tutaj definiujemy, co nasza aplikacja może, a co nie. Jeśli jest to okienko swingowe z tutoriala, to nic nie potrzebujemy. Gdy chcemy zapisywać pliki na dysku itp, to potrzebujemy dostęp, najlepiej do wszystkiego. Dokładnie takie same seciurity (ale w trochę innej formie zapisu), musi być zdefiniowane w Manifeście w JAR’ze zawierającym klasę, którą będziemy uruchamiać (z metodą main()).
  <resources>
    <j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se” 
             initial-heap-size=„64m" 
             max-heap-size=„512m" 
             java-vm-args="-ea -Xincgc"/>

Następnie mamy definicję na jakiej wersji Javy ma być odpalona docelowa aplikacja. W specyfikacji 6.0 JNLP zamiast „j2se" może pojawić się „java".

Wersja może być zdefiniowana na wiele sposobów. Możemy podać dokładnie (np.: 1.7, 1.4.2, 1.4.2_04, 1.5.0-beta2), albo większe równie niż (np.: 1.5+, 1.4.2+). Można również podać kilka wersji kolejno wg. preferencji.

Gdy chcemy jakiejś egzotycznej wersji, musimy podać atrybut href.

Na koniec możemy jeszcze zdefiniować ustawienia pamięci i przekazać jakieś flagi do JVM’a.
    <jar href="http://argouml-downloads.tigris.org/maven2/antlr/antlr/2.7.7-3/antlr-2.7.7-3.jar"/>
    <jar href="http://argouml-downloads.tigris.org/maven2/org/argouml/argouml-euml/0.34/argouml-euml-0.34.jar"/>

Dalej definiujemy nasze zależności, które Web Start ma ściągnąć. Zależności są cache’owane, więc jak podbijamy wersję biblioteki, to warto zmienić nazwę pliku. Gdy nie podamy pełnej ścieżki do pliku, to będzie ona budowana na podstawie codebase (w tag’u jnlp).
    <property name=„argouml.modules" value=";org.argouml….."    />
</resources>

W ten sposób definiujemy sobie właściwości wspólne dla wszystkich platform. Muszą one jednak się zaczynać od "javaws." lub "jnlp.”. Ta powyższa definicja z ArgoUML wg. mnie nie zadziała. Jeszcze niektóre predefiniowane propertisy (np.: http.agenthttp.keepAlive) można zdefiniować w ten sposób.

To były właściwości wspólne dla wszystkich systemów operacyjnych. Mamy jeszcze możliwość zdefiniowania właściwości specyficznych dla konkretnej platformy, np.:
  <resources os="Windows" arch="amd64">
     <property name="jnlp.abc" value=„xyz"/>
  </resources>

  <resources os="Mac OS X" arch="x86_64">
     <property name="jnlp.abc" value=„123"/>
  </resources>

Jeszcze na koniec pozostaje nam punkt wejścia do aplikacji:
<application-desc main-class=„com.mycompany.myapp.MainApp">
   <argument>arg1</argument>
   <argument>arg2</argument>
</application-desc>

Tutaj możemy dodatkowo przekazać argumenty do aplikacji. Pełen opis tego co możemy zrobić w pliku JNLP można znaleść tutaj: JNLP File Syntax.

I to już wszystko jeśli chodzi o sam plik JNLP. Przygotowujemy taki plik, wrzucamy na serwer, umieszczamy do niego link, podpisujemy nasze JAR’y, robimy je możliwe do ściągnięcia i już możemy cieszyć się Web Startem. Brzmi prosto, ale na pewno takie nie jest. W kolejnym artykule opiszę, jak można sobie trochę ułatwić życie.

czwartek, 12 sierpnia 2010

Podpisywanie apletu, czyli szybki sposób na aplikację osadzoną w przeglądarce

Dzisiaj opiszę pewną retrospekcję jak mi się przydarzyła jakiś czas temu. Przyszedł do mnie kolega (Kaktus) i się pyta mniej wiecej tak:

Kaktus: Ty Stachu, czy taką zwykłą aplikację okienkową napisaną w Swingu da się przenieść do appletu?
Ja: No da się.
Kaktus: A w takiej zwykłej aplikacji okienkowej da się jakoś prosto połączyć z bazą danych?
Ja: No da się.
Kaktus: No a da się więc z apletu połączyć się bezpośrednio z bazą danych?
Ja: No to to już nie koniecznie... Ale zobaczę co da się zrobić...

Aplety to był taki wynalazek który rozpoczął wielką ekspansję języka Java. Na konferencji SunWorld’95 pokazano przeglądarkę internetową potrafiącą wykonywać kod wewnątrz strony WWW – coś co dzisiaj nazywamy apletem. Potem zaczęto dodawać nowe funkcjonalności do języka Java, co było widoczne w kolejnych wersjach języka. Obecnie aplety nie są masowo wykorzystywane w przemyśle (zostały wyparte przez flash’a i inne podobne technologie). Piszą o nich jednak jeszcze w książkach i wykładają na uczelniach wyższych.

Dlaczego więc piszę o apletach skoro to taki staroć? Bo za pomocą apletu możemy w stosunkowo łatwy sposób (zakładając pewną znajomość języka Java) zrobić aplikację działającą w oknie przeglądarki. Takie aplikacje czasem są wymagane na studiach, a bez porządnego wprowadzenia do framework’ów Javowych ciężko się do tego zabrać. Mamy jeszcze .NET i Visual Studio, który posiada edytor stron HTML typu przeciągnij i upuść (drag and drop). Dzięki takiemu zestawowi można również szybko coś przygotować na przeglądarkę, aby pokazać prowadzącemu na studiach w celu zaliczenia pewnego przedmiotu. Ale ja nie dzisiaj o tym.

Java od początków swojego powstawania była reklamowana jako język bezpieczny i stabilny. Nigdy więcej wycieków pamięci, nigdy więcej sprzątania po sobie i obowiązują twarde restrykcje jak chcemy zrobić coś lepszego. Z tego względu też ograniczenia apletów są bardzo duże. Działają one w piaskownicy o następujących ograniczeniach:

  • nie można pozwalać uruchamiać programów na komputerze
  • nie można komunikować się z innym serwerem niż ten z którego zostały ściągnięte
  • nie można czytać, ani zapisywać plików na komputerze użytkownika
  • nie można zbierać informacji o komputerze użytkownika (poza kilkoma podstawowymi)

Pewien czas się zastanawiałem czy będzie możliwe połączenie z bazą danych z poziomu apletu. Po pewnym czasie mnie oświeciło, jak sobie przypomniałem, że kiedyś widziałem aplet który robił czego „normalnie” nie wolno. Przypomniało mi się wtedy o podpisywaniu apletów.

Wziąłem więc jakiś mój stary projekt (Swing + JDBC + MySQL) i przerobiłem go na szybko na aplet. Pierwsze uruchomienie zgodnie z oczekiwaniami zakończyło się fiaskiem:


java.security.AccessControlException: access denied (java.security.AllPermission )
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at NewJApplet.init(NewJApplet.java:23)
at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Exception: java.security.AccessControlException: access denied (java.security.AllPermission )

Trzeba więc podpisać aplet. Aby szybko to zrobić w NetBeans’ie należy kliknąć prawym na nazwę projektu i przejść do właściwości.


Następnie na zakładce Web Start zaznaczamy Self-signed. Oznacza to ze aplet będzie podpisany przez nas samych.

Przybudowujemy projekt i uruchamiamy w przeglądarce. Udało się! Dostajemy ostrzeżenie czy aby na pewno chcemy uruchomić aplet:

Klikamy Run i możemy się cieszyć apletem działającym w przeglądarce i łączącym się z bazą danych za pomocą JDBC :)

Przy okazji postanowiłem sprawdzić czy można się połączyć z hostem na innym komputerze niż ten z którego został załadowany aplet. Po jakimś czasie spędzonym na konfigurowanie firewall’i i uprawnień na bazie danych w końcu się udało. Możliwe jest więc wyjście poza piaskownice i poza serwer z którego ładowaliśmy aplet :)

Chciałbym jeszcze poruszyć temat uprawnień. W Javie jest możliwe dodawanie dodatkowych uprawnień niektórym aplikacjom za pomocą plików *.policy. W przypadku apletów nie można zdefiniować takiego pliku, aby był pobierany z serwera i użyty przy uruchomieniu danego apletu. Można jedynie ręcznie edytować na lokalnym komputerze plik java.policy, ale to odradzam.

Na koniec powiem, że przygotowując ten wpis opierałem się na książce core Java 2 Podstawy. Jest w niej również ładnie opisane jak zrobić aplikację która jest równocześnie apletem i aplikacją standalone. Polecam początkującym programistom.