JAVA exPress > Archiwum > Numer 3 (2009-03-08) > Programowanie bez słowa redeploy...

Programowanie bez słowa redeploy...

Codzienna praca developera aplikacji webowych wygląda mniej więcej tak: pisanie kodu, kompilacja, deployowanie na serwerze, testowanie, pisanie kodu, kompilacja, deployowanie, testy i tak w kółko.

Podczas gdy pisanie kodu sprawia (a przynajmniej powinno sprawiać) przyjemność, kompilacja trwa zaledwie do kilku minut tak proces wgrywania aplikacji na serwer może trwać w nieskończoność. Czy zatem nie można by pominąć tej fazy lub maksymalnie ją przyspieszyć? Okazuje się, że jest taka możliwość, a z pomocą przychodzi JavaRebel.

JavaRebel

JavaRebel to plugin dla wirtualnej maszyny Javy (JVM), który umożliwia podmianę w locie zmienionych plików .class aplikacji na serwerze. Nie musimy więc sami wysyłać na serwer całej aplikacji, która niejednokrotnie zajmuje kilka Mb, lecz JavaRebel wysyła automatycznie zmienione przez Nas pojedyncze pliki.

Licencja

Jak zatem zdobyć takie narzędzie? Najprościej będzie pobrać je ze strony producenta http://www.zeroturnaround.com/javarebel/. Niestety za posiadanie tego plugina trzeba zapłacić. Za roczną licencję przyjdzie nam wydać 99$. Istnieje również możliwość darmowego przetestowania JavaRebel.

Mam dobrą wiadomość dla posiadaczy brązowego pasa na JavaBlackBelt (http://javablackbelt.com/). Każdy posiadacz tego pasa ma możliwość otrzymania licencji za darmo. Dodam jeszcze, że licencje rozdawane są również podczas spotkań JUGów – tak zdobyłem swoją.

Przykładowa aplikacja

Pora na zaprezentowanie JavaRebel "w akcji". Do tego celu stworzę przykładową aplikację Web z wykorzystaniem frameworka Struts1, a jako serwer posłuży mi GlassFish v2.

Pierwszą czynnością jest utworzenie projektu. W NetBeans 6.5 wybieram File->New Project… i z listy wybieram Java Web->Web Application.

Projekt nazwałem JavaRebelWeb. Podczas kolejnych kroków wybieram framework Struts1.2.9 oraz zaznaczamy opcję "Add Struts TLDs" i czekam kilka chwil na utworzenie projektu. Powinna zostać stworzona struktura podobna jak na rysunku 1.

Rys 1. Struktura katalogów

Na początek proponuję stworzyć formularz, który będzie zawierał imię oraz numer identyfikacyjny. Następnie na jego podstawie zaprezentuje działanie JavaRebel.

Zacznijmy więc od utworzenia strony JSP z formularzem. W tym celu naciskamy Ctrl+N, a następnie z listy wybieramy Web->JSP. W kolejnym kroku wypełniamy pola jak zostało to pokazane na rysunku 2

Rys 2. Tworzenie strony JSP do obsługi klienta – UserPage.jsp

W wygenerowanej stronie dodajemy formularz z dwoma polami oraz przyciskiem do zatwierdzenia. Źródło strony powinno wyglądać podobnie jak w Listingu nr 1:

 

 
        <body>
          <h1><bean:message key="user.page.title" /></h1>
          <html:form action="/UserForm.do" >
            <bean:message key="user.page.name" />
            <html:text  property="name"/>
            <br />
            <bean:message key="user.page.number" />
            <html:text  property="number" />
            <br />
            <html:errors/>
            <br />
            <html:submit>Zaakceptuj! </html:submit>
          </html:form>
        </body>
 

Linting 1. Kod UserPage.jsp

Znacznik <html:errors/> umieściłem już teraz, choć będziemy go potrzebować dopiero później – przy walidacji pól.

Stwórzmy teraz klasę, która będzie odzwierciedlała pola we wspomnianym formularzu. W tym celu naciskamy Ctrl+N, a następnie z listy wybieramy Struts->Struts ActionForm Bean. W kolejnym kroku wypełniamy pola jak zostało to pokazane na rysunku 3.

Rys 3. Konfiguracja UserActionForm.java

Jak możemy zauważyć w klasie UserActionForm.java zostały utworzone dwa pole prywatne (listing nr 2). Jedno to imię, a drugie to numer – mamy więc to czego potrzebowaliśmy.

 
        private String name;
        private int number;
 

Listing 2. Pola w UserActionForm.java

Pora na utworzenie akcji, która zostanie wykonana po naciśnięciu przycisku Zaakceptuj! W tym celu naciskamy ponownie Ctrl+N, a następnie z listy wybieramy Struts->Struts Action. W kolejnym kroku wypełniamy pola jak zostało to pokazane na rysunku 4 oraz na rysunku 5.

Rys 4 Konfiguracja UserAction.java

Rys 5. Konfiguracja UserAction.java – kolejny krok

Ostatnią czynność jaką wykonamy to zmodyfikowanie pliku web.xml tak, aby naszą stroną startową była wcześniej utworzona strona UserPage.jsp (Listing 3)

 
        <welcome-file-list>
            <welcome-file>UserPage.jsp</welcome-file>
        </welcome-file-list>
 

Listing 3. Zmiana w web.xml

Tak stworzyliśmy bardzo prostą aplikację webową. Pora na sprawdzenie czy wszystko działa jak powinno. Naciskamy Shift + F11 i czekamy, aż aplikacja się zbuduje. Po zobaczeniu komunikatu BUILD SUCCESSFUL możemy sprawdzić, że pliki .class znajdują się w katalogu JavaRebelWeb\build\web\WEB-INF\classes\. Teraz pozostaje Nam przystąpić do konfiguracji serwera, tak aby potrafił się komunikować z JavaRebel.

Aby serwer wykorzystywał wspomniany plugin wystarczy dodać dwie linijki. Dla serwera GlassFish należy je umieścić w pliku domain.xml znajdującym się w katalogu config naszej domeny. Owe najważniejsze linijki zostały pokazane w listingu nr 4.

        -noverify -javaagent:C:\Programowanie\Java\JavaRebel\javarebel-1.2.2\javarebel.jar
        -Drebel.dirs=G:\Sandbox\JavaRebelWeb\build\web\WEB-INF\classes\
        

Listing 4. Konfiguracja JavaRebel

Pierwsza z nich wskazuje na położenie pliku JAR javarebel.jar, natomiast druga informuje jaki katalog ma zostać "śledzony" przez JavaRebel w poszukiwaniu zmienionych klas.

Po zapisaniu zmian uruchamiamy serwer. Jeśli wszystko zostało poprawnie skonfigurowane na ekranie pojawi się komunikat podobny jak w listingu nr 5.

        ##########################################################

         ZeroTurnaround JavaRebel 1.2.2 (200812021546)
         (c) Copyright Webmedia, Ltd, 2007, 2008. All rights reserved.

         This product is licensed to Marcin Gadamer (Personal)

        ##########################################################

        JavaRebel: Directory 'G:\Sandbox\JavaRebelWeb\build\web\WEB-INF\classes' will be monitored for class changes.
        

Listing 5. Konsola z JavaRebel

Nie pozostaje nic innego jak standardowo zdeployować utworzoną wcześniej aplikację na serwerze.

Zabawę czas zacząć...

W ulubionej przeglądarce podajemy adres http://localhost:8080/JavaRebelWeb/, i po naciśnięciu ENTER powinna pokazać się strona UserPage.jsp, którą wcześniej przygotowaliśmy, tak ja na rysunku nr 6.

Rys 6. Strona główna aplikacji

Zabawę zacznijmy od utworzenia strony JSP, która się wyświetli po podaniu poprawnych danych – nazwijmy ją GoodUser.jsp. Nie będę zamieszczał tutaj szczegółów tworzenia strony. Jedynie na co warto zwrócić uwagę, to na wykonanie w pliku struts-config.xml odpowiedniej modyfikacji jak zostało to przedstawione w listingu nr 6.

 
        <action input="/" name="UserActionForm" path="/UserForm" scope="session"
            type="pl.gadamer.javarebelweb.action.UserAction">
              <forward name="success" path="/GoodUser.jsp" />
        </action>
 

Listing 6. Zmiana w struts-config.xml

Ostatnią rzeczą jest redeploy aplikacji. Dlaczego redeploy? Ponieważ stworzyliśmy nową stronę JSP, a nie była to zmiana w klasie *.java

Gdzie stwierdzamy czy dane podane są poprawnie, czy błędnie? Odpowiedzialna jest za to metoda validate w UserActionForm.java.

NetBeans wygenerował nam metodę, w której sprawdzamy czy pole name jest wypełnione. Jeśli nie jest wypełnione, to komunikat błędu pojawi się na stronie UserPage.jsp w miejscu wcześniejszego dodania znacznika <html:errors/>.

Spróbujmy zmodyfikować metodę tak, aby pole name musiało zawierać literę "a". Przykładowy kod jest zamieszczony w listingu nr 7. W pliku z wiadomościami pamiętajmy o dodaniu odpowiedniego klucza.

 
        public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
            ActionErrors errors = new ActionErrors();
            if (!getName().contains("a")) {
                errors.add("name", new ActionMessage("error.name.wrong"));
            }
            return errors;
        }
 

Listing 7. Imię zawiera literę "a"

Budujemy aplikację i odświeżamy stronę z formularzem. Na pierwszy rzut oka nic się nie zmieniło. Spójrzmy zatem do konsoli. Tam możemy znaleźć wpis jak w listingu nr 8.

        JavaRebel: Reloading class: 'pl.gadamer.javarebelwar.actionform.UserActionForm'
        

Listing 8. Działanie JavaRebel

Czyli jednak coś się zmieniło! W tle omawiany plugin podmienił klasę UserActionForm.class.

Sprawdźmy czy, aby na pewno. W polu imię wpisujemy "Robert" i naciskamy Zaakceptuj! Pojawił się napis "Podano błędne imię!" jak na rysunku nr 7, czyli walidacja zadziałała. Wpiszmy zatem imię z literką "a" - proponuję Marcin. Identyfikator jak poprzednio wpisujemy dowolny. Po naciśnięciu przycisku Zaakceptuj! zostajemy przeniesieni na stronę GoodUser.jsp, więc dane są prawidłowe.

Rys 7. Walidacja formularza – dane nieprawidłowe

Dodajmy dodatkowo jeszcze walidację dla numeru. Dla przykładu niech pole liczba odpowiada liczbie słów w imieniu. Przykładowy kod został zamieszczony w listing nr 9.

 
        public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
            ActionErrors errors = new ActionErrors();
            if (!getName().contains("a")) {
              errors.add("name", new ActionMessage("error.name.wrong"));
            }
            errors.add(validateNumber());
            return errors;
          }
 
          private ActionErrors validateNumber() {
            ActionErrors errors = new ActionErrors();
            int nameLength = getName().length();
            if (getNumber() != nameLength) {
              errors.add("number", new ActionMessage("error.number.wrong"));
            }
            return errors;
          }
 

Listing 9. Walidacja numeru

Podobnie jak poprzednio jedynie budujemy aplikację, a następnie odświeżamy stronę główną. W konsoli znów pojawia się informacja o podmianie klasy UserActionForm.class przez JavaRebel. Zauważmy, że została dodana teraz nowa metoda, a nie jak poprzednio zmodyfikowana jedynie istniejąca. (Zakładam, że do poprawnego działania dysponujemy już kompletnym plikiem z wiadomościami i nie musimy w nim dokonywać zmian).

Jak już wspomniałem wcześniej JavaRebel doskonale działa jednak tylko dla zmian w plikach *.class. Podczas zmian w pliku *.jsp lub pliku *.properties musimy wykonać ponowny deploy aplikacji.

Wracając do aplikacji zachowanie jest takie jak chcieliśmy:
- Dla niepoprawnego pola name oraz niepoprawnego pola number otrzymujemy dwa komunikaty o błędzie,
- Dla jednego błędnego pola otrzymujemy tylko jeden komunikat dla tego pola,
- Gdy we wpisanym imieniu występuje litera "a" oraz gdy została podana odpowiednia liczba następuje przejście do drugiej strony

Możliwości

JavaRebel oferuje znacznie więcej możliwości. Możemy za jej pomocą dodawać i usuwać metody, dodawać i usuwać konstruktory, dokonywać zmian w adnotacjach oraz (od wersji 2.0) dodawać nowe klasy bez konieczności ponownego deployu.

Jest również wsparcie dla frameworków takich jak Spring, Struts2 oraz Tapestry4.

Lista serwerów na jakich możemy korzystać z JavaRebel również jest spora. Obejmuje ona m.in. serwery:
- IBM WebSphere BEA,
- Weblogic 8.x, 9.x, 10.x,
- GlassFish v2,
- Oracle OC4J 9.x, 10.x,
- Tomcat 4.x, 5.x, 6.x,
- JBoss 3.x, 4.x (Java 5 lub 6),
- Jetty 5.x, 6.x (Java 5 lub 6),
- Equinox OSGi (including Eclipse plugins)

Podsumowanie

Uważam, że JavaRebel doskonale się sprawdzi, gdy w aplikacji dokonujemy zmian w istniejącym już kodzie, ponieważ jeśli przychodzi Nam często dodawać nowe pliki to i tak wymaga to ponownego deployu. Doceniony zostanie również w aplikacjach, których deploy trwa kilka, a może nawet kilkanaście minut.

Mam nadzieję, że na tych kilku stronach udało mi się choć w skrócie zaprezentować działanie pluginu JavaRebel. Niewątpliwie jest on godny zainteresowania i przetestowania czy opłaca się wydać blisko 100$ na licencję. Zaoszczędzony tak czas można wykorzystać np. na przeczytanie kolejnego artykułu w JAVA exPress...

Nie ma jeszcze komentarzy.

Tylko zalogowani użytkowincy mogą pisać komentarze

Developers World