Piwo to moje paliwo
February 7th, 2010I jebać zakaz reklamy alkoholu
Zdecydowanie wygodniejszy do pisania postów z komórki niż przegladarka. Zapisuje sie na betatestera.
W projekcie zaczynamy używać biblioteki iText i JasperReports. Wszystko ładnie pięknie, ale:
Pierwszy problem to dość poważna wpada ekipy od iTexta. Otóż wersji 5 nie ma w repo mavena. Dopinamy więc ja ręcznie. Następnie okazuje się, że JR wykorzystuje iText, ale w wersji 2. niby wszystko bangla, ale różnica pomiędzy iText 5 i 2 jest niewielka jednak bardzo bolesna. Polega na zmianie nazw pakietów. Zamiast com.lowagie.text w wersji 5 mamy com.itextpdf.text. Zatem musimy mieć dwie różne biblioteki w projekcie. Jeżeli w mavenie podepniemy z rozpędu iText 5 do grupy com.lowagie to oczywiście wersja 2 zostanie zignorowana przy sprawdzaniu zależności JR. Spowoduje to brak klas z pakietu com.lowagie.text i tym samym radosna wyjebkę całości. Poniżej poprawny kawałek pom.xml:
Listing 1. Poprawnie złożony pom.xml
itext itext 5.0.0 system ${basedir}/libs/iText.jar com.lowagie itext 2.1.7 jasperreports jasperreports 3.5.3
tak będzie git.
Kolejna ciekawostka to błąd java.lang.NoClassDefFoundError: org/codehaus/groovy/control/CompilationFailedException w trakcie generowania raportu. Okazuje się, że jeżeli używa się iReport do tworzenia szablonów to do tagu jasperReport jest dodawany atrybut language=”groovy”. Na rozwiązanie problemu są dwie drogi. Pierwsza dopiąć Groovy, druga wyjebać atrybut. Pierwsza metoda wymaga jednak użycia paczki groovy-all. Dodajemy zatem:
Listing 2. groovy-all w pom.xml
org.codehaus.groovy groovy-all 1.7.0
Zaletą tego rozwiązania jest możliwość, dania użytkownikom iReport i powiedzenie, by sami ładowali raporty na serwer.
koniec
uff…
No właśnie co oznacza honorW? Wiele osób, szczególnie polityków, mówi o honorze o hańbie i o tym jacy to oni nie są honorowi. Jest jednak jeden człowiek, który choć nie uczestniczy już w życiu publicznym może o sobie powiedzieć, że jest honorowy. Generał Wojciech Jaruzelski w swojej opinii na temat filmu “Generał” mówi:
twórcy filmu przeinaczyli fakty. Zasugerował też, że działali na polityczne zamówienie. Dodał, że autorzy filmu nie są w stanie go obrazić, znieważyli natomiast wielu ludzi, którzy przeszli tę samą drogę, co on. Jaruzelski powtórzył, że nie chce się wybielać i wyraża żal za wszystkie krzywdy ludzkie, do których doszło w okresie, gdy pełnił wysokie funkcje wojskowe i państwowe.
Wiecie dlaczego jest człowiekiem honoru? Ponieważ nie zasłania się immunitetem, nie tłumaczy “dwoma jabłkami”, ale otwarcie mówi o swoich działaniach, nie wypiera się ich i bierze za nie odpowiedzialność. Niezależnie od tego czy oceniamy go źle, czy bardzo źle (bo dobrze to on nie działał) należy uznać, że jako jeden z nielicznych polityków potrafi odpowiadać za swoje czyny.
Współczesny człowiek honoru potrafi wziąć odpowiedzialność za swoje działania.
Strona sun.com oficjalnie zniknęła z sieci. Adres przekierowuje na oracle.com. To koniec pewnej epoki…
coby nie było java.sun.com działa dalej.
Tak minie coś na Bathory naszło… a i wykonanie zacne.
Projekt “prosty bash.org w jeden dzień” ciągnie się już drugi dzień
W dwóch wpisach przybliżyłem już jak się ma sprawa z modelem danych w PF. Dziś opiszę jak od podstaw stworzyć kontroler i widok do jego obsługi. Generalnie zasady są proste. Rozszerzamy klasę Controller i dodajemy mapowania w pliku routes. W praktyce jest tylko trochę trudniej
Nasz kontroler będzie pozwalał na dodanie cytatu do bazy. Cytat, będzie niewidoczny na stronie głównej dopóki administrator go nie zaakceptuje. Proste
Nasz kontroler będzie posiadał akcję addQuoteAction oraz metodę addQuote, która będzie renderować ekran z formularzem. Na początek wyrenderujemy sobie ekran z formularzem.
Listing 1. AddQuoteController.addQuote()
package controllers;
import play.mvc.Controller;
public class AddQuoteController extends Controller {
public static void addQuote() {
render();
}
}
W sumie tak wygląda najprostszy kontroler w Play Framework. Metoda render przyjmuje zmienną liczbę parametrów, które są bindowane do zmiennych w szablonie. To jednak za chwilę. Najpierw dodamy jeszcze jedną metodę.
Listing 2.
package controllers;
import java.util.GregorianCalendar;
import net.sf.oval.constraint.MinLength;
import models.Quote;
import play.data.validation.Min;
import play.data.validation.Required;
import play.mvc.Controller;
public class AddQuoteController extends Controller {
public static void addQuote() {
render();
}
public static void addQuoteAction(
@Required(message = "Wymagane!") @MinLength(value = 10, message = "Conajmniej 10 znaków!") String content) {
if (validation.hasErrors()) {
render("AddQuoteController/addQuote.html");
}
Quote newQuote = new Quote();
newQuote.content = content;
newQuote.accepted = false;
newQuote.addTime = new GregorianCalendar();
newQuote.avgNote = 0;
newQuote.numberOfNotes = 0;
newQuote.save();
Application.index();
}
}
Dodaliśmy metodę addQuoteAction. Jako parametr przyjmuje ona klucz content. Klucza tego będziemy używać za chwilę w szablonie. Przy okazji zastosowałem dwie adnotacje. Pierwsza @Required oznacza, że parametr jest wymagany. Druga @MinLenght to minimalna wielkość parametru, przy czym w przypadku obiektów String oznacza to długość napisu. W ten magiczny sposób odrobiliśmy walidację. Jeżeli w walidatorze są błędy to przekierowujemy całość na stronę dodawania cytatu. I tu kolejna rzecz z dupy trochę.
W Springu była sobie klasa ModelAndView, która pozwalała na wykonywanie różniastych ekscesów z przekazywaniem sterowania. W skrajnym przypadku pozwalała ona na przekierowanie obsługi do innego kontrolera, pobranie wyników przechowywanych właśnie w ModelAndView zwróconym przez ten kontroler i przekazanie ich dalej do renderera. Tu niestety musimy wywoływać metodę render z parametrem w postaci String. Dla mało kumatych podpowiem, że nie można tego sprawdzić w trakcie kompilacji więc tracimy wszystkie zyski kontroli typów. No, ale jak się nie ma co się lubi to się lubi co się ma… jak mawiał pewien stary syfilityk.
Jeżeli nie ma błędów to tworzymy nowy cytat, dodajemy go do bazy i renderujemy stronę główną. Banalnie proste. Tak proste, że każdy 13-nastoletni specjalista od php z adhd będzie wstanie coś podobnego zrobić (i stać się specjalistą od PF).
Na obecnym etapie mamy gotowy kontroler, który należało by jeszcze przetestować, ale na razie sobie to odpuszczę. Testowanie w PF jest mocno dziwne, a zatem na kolejny raz się temu przyjrzymy. Przy okazji będę narzekał na gówniany pomysł na wywoływanie akcji kontrolerów (chętni mogą już w teraz w komentarzach wpisywać swoje pomysły, dlaczego ten model jest gówniany).
O czym to ja… a właśnie mamy kontroler, ale nie mamy jeszcze odpowiadającego mu widoku. Stwórzmy zatem prosty widok, który będzie zawierał pole do wpisywania komentarza i przycisk wyślij.
Play Framework generuje widoki w oparciu o język szablonów, który znowuż korzysta z GroovyW. Nie jest on trudny. Pozwala na tworzenie całkiem zgrabnych stron, a i można własne makra tworzyć.
Tworzymy zatem nowy plik w katalogu app/views/AddQuoteController i nazywamy go addQuote.html. Jego zawartość jest prosta, a to dzięki mechanizmowi rozszerzania szablonów oferowanym przez PF.
Listing 3. kompletny addQuote.html
#{extends 'main.html' /} #{set title:'Cytaty - dodaj własny' /}
#{form @AddQuoteController.addQuoteAction()}
<div>
<textarea name="content" id="content" cols="40" rows="5"></textarea>
#{ifErrors}
#{list items:errors, as:'error'}
#{if "content".equals(error.getKey())}
<p class="error">
${error}
</p>
#{/if}
#{/list}
#{/ifErrors}
</div>
<input type="submit" value="Dodaj!" />
#{/form}
Elegancko. W pierwszej linii importujemy się do szablonu strony main.html (o szablonach kiedy indziej) i nadajemy tytuł naszej stronie. Następnie tworzymy formularz, który jako akcję wykona AddQuoteController.addQuoteAction(). Nie podoba mi się obsługa błędów. Z drugiej strony kilkukrotne przelecenie przez krótką listę można wybaczyć. No chyba, że coś w API przeoczyłem (na pewno można zrobić to ładniej).
Wszystko ładnie pięknie, ale jeszcze to nie koniec naszej pracy. Najpierw musimy dodać link do strony głównej (i ją napisać), ale pominę to, ponieważ sposób walki ze stroną główną chciałbym omówić przy okazji szablonów. No właśnie link…
Jest sobie plik conf/routes, który zawiera informacje na temat tego jak wygląda mapowanie pomiędzy adresami URL, a kontrolerami. Normalnie wykonalibyśmy taką operację w pliku web.xml, ale PF upraszcza życie. Idea jest prosta. Programista definiuje sposób zasady routingu, a PF odpowiednio robi dobrze. Dodanie naszego mapowania jest bardzo proste. Zresztą była już o tym mowa przy okazji modułu CRUD. Nasza reguła wygląda tak:
Listing 4. Reguła dla AddQuoteController
GET /addQuote AddQuoteController.addQuote
Play Framework udostępnia programistom stosunkowo dobry i wydajny sposób tworzenia aplikacji. Dzięki zastosowaniu zasady COC i sztywnemu się jej trzymaniu (co niepomiernie potrafi wkurwić) można w miarę szybko prototypować aplikację. Dodatkowym plusem jest bardzo prosty, ale elastyczny język szablonów widoku. Dzięki czemu przyuczenie do zawodu nawet debilnego programisty php z adhd nie zajmuje za dużo czasu.
Obecnie chcę rozczaić jak PF współpracuje z GWT.
W piątek po południu przybył do mnie mój nowy telefon. Samsung i7500 Galaxy. Na pokładzie Android, aparat 5mpx, ekran dotykowy. Brak normalnej klawiatury.
W pudełku znajdziemy telefon, zasilacz, kabelek USB, słuchawki douszne, płytkę z softem Samsunga dla MS i instrukcję. Całość schludnie popakowana w woreczki i styropian.
Telefon jest “cegłowaty” w porównaniu z moim stary C65. Aparat jest lżejszy i cieńszy, ale szerszy i dłuższy przez co trochę inaczej układa się w ręku. Otwarcie obudowy nie stanowi problemu. Podobnie jak montaż karty SIM i akumulatora. Niestety by zamontować kartę microSD też trzeba zdjąć obudowę. Z drugiej strony kartę tą można wymienić bez wyłączania urządzenia, ponieważ slot nie jest blokowany przez akumulator.
Całość jest w estetycznej błyszczącej czerni.
Przy pierwszym uruchomieniu system wydaje jakieś dziwne dźwięki. Na cale szczęście zestaw dzwonków jest dość duży i można sobie na spokojnie wybrać odpowiedni zestaw. Dostęp do menu z różnymi aplikacjami, ustawieniami i kontaktami jest bardzo intuicyjny. Jeżeli jednak nie miałeś do czynienia z ekranem dotykowym to może okazać się, że na początku będą małe problemy. Trzeba się przyzwyczaić.
Konfiguracja i dostosowanie do własnych potrzeb jest bardzo prosta. Menu jest w języku polskim więc nawet osoby o ubogim słownictwie nie powinny mieć problemu. Niestety nie ma menu w wersji klingońskiej.
Początkowo miałem problem z pisaniem na klawiaturze dotykowej. Nawet po obróceniu ekranu przyciski okazały się dużo za małe. Praktyka czyni jednak mistrza. Podobnie rzecz ma się z przeglądaniem stron internetowych. Trzeba dużo cierpliwości, ale mam tez okazję zobaczyć jak na tego typu urządzeniu wygląda na przykład koziolekweb. Wygląda średnio.
Bardzo łatwo jest skonfigurować obsługę sieci WiFi. Tak samo jak dość łatwo jest uruchomić moduł GPS. Niestety, żeby działał poprawnie musi mieć dostęp do sieci. Przeglądarka internetowa jest dobra. Ma całkiem duże możliwości.
Ostatnim elementem jest dostęp do Android Market. Całkiem wygodny i intuicyjny. Cóż więcej? Mieć trzeba tylko dobre łącze.
Telefon przypadł im do gustu i mam nadzieję, ze posłuży mi przez najbliższe kilka lat. Polecam go osobą, które potrzebują telefonu + dodatki, a nie dodatki + telefon.
Jestem w trakcie tworzenia aplikacji “prosty bash.org w jeden dzień” i naciąłem się na ciekawego buga w PF 1.0 b833. Żeby zrozumieć skąd on się wziął należy trochę przybliżyć czym jest moduł CRUD w Play Framework.
Pod tą nazwą kryje się grupa frameworków, które udostępniają programistom zestaw narzędzi pozwalających na automatyczne tworzenie klas CrudDAO. Idea zakłada, że programista na przykład tworzy klasę modelu, która rozszerza klasę abstrakcyjną. Klasa abstrakcyjna dostarcza metod CRUD. Innym podejściem jest dynamiczne tworzenie metod i zapytań tak jak jest to realizowane w Grails. W każdym bądź razie w Play mamy do czynienia z pierwszą metodą. Opis tworzenia klas modelu znajdziecie tu.
Jeżeli chcemy uruchomić moduł CRUD w Play Framework to w pliku application.conf należy od-komentować linijkę
Listing 1. uruchomienie modułu CRUD
module.crud=${play.path}/modules/crud
Następnie w pliku routes należy włączyć mapowanie do modułu CRUD:
Listing 2. konfiguracja mapowań
* /admin module:crud
No i gotowe. Należy jeszcze raz podpiąć projekt do naszego IDE. Od tego momentu pod adresem /admin/ mamy do dyspozycji całkiem zgrabny panel do zarządzania naszymi obiektami.
Niestety w buildzie 833 jest bug. Otóż nie można posortować listy obiektów. Każda próba sortowania powoduje, że zawsze dostaniemy obiekty posortowane malejąco po id. Trochę do dupy… Na całe szczęście jest obejście. Moduł CRUD jak łatwo zauważyć dodał nam klasę CRUD i cały pakiet crud. Wystarczy zatem tak jak opisałem w zgłoszeniu zmienić trzy linijki.
I tyle. Generalnie CRUD z PF jest bardzo wdzięcznym podejściem do problemu i pozwala na szybkie i stosunkowo łatwe tworzenie modelu bez potrzeby kombinowania z kodem. Dostajemy na talerzu elegancki interfejs zarówno od strony programisty jak i użytkownika.
Jest kilka bardzo prostych metod, które pozwalają na bardzo dobre polepszenie jakości naszego życia i pracy z systemem Ubuntu. Niektóre z nich działają na wszystkich linuxach i warto je stosować jako obowiązkowe kroki po instalacji systemu.
Każdy współczesny system operacyjny wymusza na kompilatorze tworzenie kodu wynikowego, w którym elementy związane z bibliotekami zewnętrznymi są tylko zaślepkami. Przy uruchomieniu programu następuje proces dynamicznego łączenia (linkowania) w którym zaślepki są zastępowane właściwymi odwołaniami do kodu w bibliotekach . Proces ten powoduje, że uruchomienie programu jest wydłużane o ten czas. Przykładowo OO 3.1 wstawał na moim kompie “świeżo uruchomionym” około 15 sekund przy pierwszym uruchomieniu i około 5-7 sekund za każdym kolejnym uruchomieniem w danej sesji. Dużo… jednakże wystarczy zainstalować pewien programik, który bardzo ułatwi nam życie.
Listing 1. instalacja prelink
root$> apt-get install prelink #... komunikaty instalacji root$> prelink -amR
Co się stało? Prelink to taka sprytna biblioteka, która na podstawie informacji z kodu źródłowego potrafi zamienić dynamiczne łączenie na statyczne referencje. Niby nic nadzwyczajnego. Robi to samo co linker tyle tylko, i tu jest pies pogrzebany, że dokonuje tej operacji na kodzie wykonywalnym. Innymi słowy modyfikuje kod programu tak by w trakcie uruchomienia nie było potrzeby dynamicznego łączenia. Wada… po każdym updacie bibliotek trzeba jeszcze raz go zapuścić. No, ale cóż… raz się żyje.
Program posiada oczywiście opcję undo
Listing 2. Prelink undo
root$> prelink -au
Którą MUSISZ uruchomić jeżeli chcesz bezpiecznie usunąć prelink. Wierz mi, nie będziesz chciał. OO 3.1 poprawił swoje czasy do 5 sekund przy pierwszym i około 3 przy każdym kolejnym uruchomieniu w danej sesji.
Drugim programem jest preload, który wykorzystuje metody stochastyczne do przewidywania jakie dane będą potrzebne w następnej kolejności i je zawczasu ładuje. Problemem jest, niestety, szybkie wyczerpywanie się RAM, co powoduje, że nie można odpalić JVM. Cóż… lepszą metodą jest przejście na 64-bity i włożenie z 12GB RAMu… powinno styknąć.
Na koniec instalacja i uruchomienie:
Listing 3. instalacja preload
root$> apt-get install preload #... komunikaty instalacji root$> /etc/init.d/preload start
Ręczne uruchomienie nie powinno się wydarzyć, ale nie zawsze automatyczne zaskoczy.
Tu będzie trochę inaczej. Jeżeli masz kilka rdzeni można poeksperymentować ze sposobem obsługi współbieżności przy starcie usług. W pliku /etc/init.d/rc należy odszukać linijkę CONCURRENCY=’none’ i zamienić ją na CONCURRENCY=’shell’. Spowoduje to, że usługi będą uruchamiane równolegle, a nie szeregowo. Może to doprowadzić do dość widowiskowego wyjebania się systemu łącznie z paniką jajka. Przyczyną może być zależność jakiś nietypowych usług. Odzyskiwanie… uruchomić z LiveCD lub w singlu i przywrócić pierwotną konfigurację. System wstaje rzeczywiście trochę szybciej.
Bardzo podobną metodą jest zmiana działania skryptu rc. No ale to jest dla hardkorów, którzy rozumieją jak on działa.