Projewski’s Weblog

marzec 14, 2008

FOP Apache’a i polskie czcionki dla PDF’a

Kategoria wpisu: Java — projewski @ 3:00 pm

Ostatnio pobrałem sobie ze strony Apache’a pakiet fop-0.94. Warto wspomnieć, do czego takowy pakiet służy. Otóż wykonuje on, poprzez odmianę transformaty XSL, zwaną XSL-FO, generowanie dokumentu w wybranym formacie - najczęściej chodzi o PDF oraz o PS.

 Zadaniem, które sobie postawiłem było wygenerowanie pliku PDF z polskimi krzaczkami. Samo uruchomienie pakietu nie nastręcza kłopotów. Wystarzy rozpakować pobrany pakiet i uruchomić polecenie fop w systemie Linux’owym, lub fop.bat, jeżeli jest to Windows. Lista parametrów pięknie pokaże się naszym oczom. Standarodowe używanie programu polega na ładowaniu plików .fo i generowaniu powiedzmy .pdf. Lepszą zabawę uzyskujemy wykorzystując plik transformacji .xsl, który na bazie pliku z danymi .xml generuje nam plik typu .fo, z którego powstaje upragniony .pdf czy .ps.

Problem z jakim się napotkałem to oczywiście polskie czcionki, które, jakżeby inaczej, w domyślnej konfiguracji są niezbyt dostępne dla użytkownika. Zadanie to można zrealizować poprzez wykorzystanie pliku z czcionkami, które akceptuje fop. A akceptuje dwa dość popularne typy: TrueType oraz PostScript Type 1. Posiadając system Windows możemy odnaleźć czcionki TrueType z polską czcionką i spróbować je wykorzystać. Pliki posiadają rozszerzenie .ttf. Oczywiście polecam wcześniej przyjrzeć się, co takowy plik tak naprawdę zawiera.

Aby wykorzystać wybraną czcionkę powinniśmy w pierwszej kolejności wygenerować tak zwane font metrics, którymi FOP będzie się posługiwał. Poniżej zamieszczam kod skryptu sh, który używałem do generowania takowego pliku. Skrypt używa w tym celu klasy TTFReader, która dostarczona jest z FOP’em. Jeżeli import odbywa się z czcionek True Type 1, to należy wykorzystać klasę PMFReader.

#!/bin/sh
#
# sciezka do katalogu domowego Java
JAVA_HOME=”/opt/java”;
# sciezka do pliku fop.jar
FOP_PATH=”/opt/java/fop/build”;
# sciezka do jar’ow uzywanych przez fop’a
LIB_PATH=”/opt/java/fop/lib”;
#
$JAVA_HOME/bin/java -cp $FOP_PATH/fop.jar:$LIB_PATH/avalon-framework.jar:$LIB_PATH/xml-apis.jar:$LIB_PATH/xercesImpl.jar:$LIB_PATH/xalan.jar:$LIB_PATH/commons-logging-1.0.4.jar:$LIB_PATH/commons-io-1.3.1.jar org.apache.fop.fonts.apps.TTFReader $1 $1.xml

Jeżeli posiadamy czcionki bold oraz italic, to dla nich również generujemy pliki font metrics.

Teraz pliki czcionek oraz wygenerowane font metrics umieszczamy w jakimś miejscu na dysku, niech to będzie /usr/local/lib/fop. Potrzebny jest nam teraz plik konfiguracyjny, który pozwoli na podłączenie takich czcionek. Będzie on wyglądał tak:

<configuration>
<renderers>
<renderer mime=”application/pdf”>
<fonts>
<font metrics-url=”file:///usr/local/lib/fop/czcionka.ttf.xml” kerning=”yes” embed-url=”file:///usr/local/lib/fop/czcionka.ttf”>
<font-triplet name=”Czcionka” style=”normal” weight=”normal”/>
</font>
<font metrics-url=”file:///usr/local/lib/fop/czcionka-bold.ttf.xml” kerning=”yes” embed-url=”file:///usr/local/lib/fop/czcionka-bold.ttf”>
<font-triplet name=”Czcionka” style=”normal” weight=”bold”/>
</font>
<font metrics-url=”file:///usr/local/lib/fop/czcionka-italic.ttf.xml” kerning=”yes” embed-url=”file:///usr/local/lib/fop/czcionka-italic.ttf”>
<font-triplet name=”Czcionka” style=”italic” weight=”normal”/>
</font>
</fonts>
</renderer>
</renderers>
</configuration>

Plik konfiguracyjny zawiera ścieżki, wskazujące na pliki czcionek oraz ich odpowiednie font metrics. Oczywiście konfiguracja może również zawierać inne dane konfiguracyjne, jakie używamy do fop’a. Te określone tutaj określają zestaw czcionek, używanych podczas renderowania dokumentu PDF - na co wskazuje atrybut mime=”application/pdf”, użyty dla elementu renderer. Aby użyć pliku konfiguracyjnego wykorzystujemy polecenie fop z parametrem -c nazwa-pliku-konfiguracyjnego.

To co jest jeszcze istotne to fakt, że podczas generowania pliku PDF/PS, fop automatycznie tworzy w katalogu domowym bieżącego użytkownika folder .fop, w którym zostaje zawarty cache dla czcionek, jakie są wykorzystywane. Warto o tym pamiętać w przypadku korzystania z tego narzędzia poprzez np. zestaw narzędzi apache + php, gdy mamy skonfigurowanego użytkownika dla aplikacji. Fop będzie wtedy próbował założyć folder w katalogu domowym takiego użytkownika - dobrze więc sprawdzić, czy użytkownik ma uprawnienia do zapisywania w takim katalogu. (Można również utworzyć samodzielnie folder .fop, w jego katalogu domowym i nadać na nim odpowiednie uprawnienia własności/zapisu).

Więcej na temat fop‘a znajdziemy na stonie domowej projektu Apache’a http://xmlgraphics.apache.org/fop/

styczeń 11, 2008

JBoss, EJB 3 i StreamCorruptedException

Kategoria wpisu: Java — projewski @ 10:36 przed południem

Ostatnio wykonywałem stawianie serwera JBoss 4.0.5 z pakietem patchującym jboss-EJB-3.0_RC9_Patch_1, który miał zapewnić mi rozszerzenie do funkcjonalności EJB 3. Uruchamiałem JBoss w konfiguracji default. Podczas uruchamiania otrzymałem komunikat, którego finałowym powodem był brak klasy org.jboss.cache.TreeCache. Klasę odnalazłem w pakiecie jboss-cache.jar znajdującą się w konfiguracji all. Poza tym jar’em okazało się również niezbędne dodanie jgroups.jar z podobnej konfiguracji. I teraz po uruchomieniu okazało się, że ustawicznie otrzymuje komunikat, wyglądający mniej więcej tak:

2007-05-29 19:31:15,453 WARN [org.jgroups.protocols.UDP] packet from /X.X.X.X :P has different version from ours
2007-05-29 19:31:27,671 ERROR [org.jgroups.protocols.UDP] exception=java.io.StreamCorruptedException: invalid stream header
at java.io.ObjectInputStream.readStreamHeader (ObjectInputStream.java:764)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:277)
at org.jgroups.protocols.UDP.handleIncomingUdpPacket(UDP.java:670)
at org.jgroups.protocols.UDP.run(UDP.java:249)
at java.lang.Thread.run(Thread.java:595)

Podczas poszukiwań w internecie próbowałem ustalić “Skąd się to diabła bierze ??” oraz “Jak to wyłączyć ?”. Dowiedziałem się, że głównym sprawcą zamieszania jest opcja grupowania w klastry (group clustering). Opcja ta oczywiście dostępne jest wyłącznie w dystrybucji all. Moje przeniesienie plików jar, w celu zniwelowania problemu przyczyniły się do powstania tego kłopotu.

Tak więc postanowiłem wykonać operację w drugą stronę i dowiedzieć się, co spowodowało narodzenie się wymagania klas typu TreeCache i JGroups. Przyczyną był oczywiście ów patch, który rejestrował dwa serwisy, korzystające z tej usługi. Usunąłem więc pliki, które są odpowiedzialne za taki stan rzeczy: ejb3_clustered_sfsbcache_service.xml oraz ejb3_entity_cache_service.xml (znajdujące się w folderze deploy). Oczywiście nie zapomniałem również o pozbyciu się jgroups.jar oraz jboss-cache.jar (z folderu lib). Po tych czystkach wszystko poszło pięknie i bez problemów.

Oczywistym jest, że zacząłem się zastanawiać nad sposobami zniwelowania problemu w przypadku, kiedy posiadam zainstalowany clustering. Okazało się, że powodem jest istnienie innych serwerów w lokalnej sieci, które mają inną wersję JBoss’a, a które próbują utworzyć ze mną wspólną grupę. Każda z takich grup używa swoją prywatną nazwę oraz określenie adresu i portu dla multicastingu. Z pomocą nad rozwikładniem zagadki przyszły mi poniższe dwa artykuły:

http://docs.jboss.org/jbossas/jboss4guide/r4/html/jbosscache.chapt.html , który opisuje sposób konfigurowania JGroups (i tu mała uwaga, opcja discard_incompatible_packets w mojej wersji nazywa się discard_incompatibe_packets z powodu literówki, która została później poprawiona w JBoss)

http://wiki.jboss.org/wiki/Wiki.jsp?page=TwoClustersSameNetwork , który opisuje jak skonfigurować dwa odrębne klastry w tej samej sieci - co sprawdziłem i stwierdzam, że funkcjonuje to poprawnie (plik cluster-service.xml jest dostępny w konfiguracji all). Problemem, jaki należy później jeszcze rozwiązać jest skonfigurowanie plików EJB 3, które usuwałem, tak, aby nie kolidowały z odpowiednikami, jakie znajdują się w naszej sieci lokalnej.

październik 29, 2007

Strumień ByteArrayOutputStream

Kategoria wpisu: Java — projewski @ 11:15 przed południem

Oto, co dziś się dowiedziałem, a czego jeszcze nie przetestowałem:

Implementacja Apache strumienia ByteArrayOutputStream jest szybsza i zajmuje mniej pamięci od podobnej implementacji Sun’a. Dlatego znacznie lepszym pomysłem jest stosowanie klasy org.apache.commons.io.output.ByteArrayOutputStream niż klasy java.io.ByteArrayOutputStream. Z testów porównawczych, wykonanych na pliku o rozmiarze 90 MB, otrzymano następujące informacje:

Sun JDK wykonywał wczytanie w ciągu 2300 ms i zajął 210 MB pamięci
Apache wykonał wczytanie w ciagu 1300 ms i zajął 140 MB pamięci

Blog at WordPress.com.