<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0"><id>tag:blogger.com,1999:blog-3027091649644802032</id><updated>2012-03-25T23:29:48.408+02:00</updated><category term="hack" /><category term="entry-point" /><category term="GWT" /><category term="double" /><category term="funny" /><category term="Designer" /><category term="Portal" /><category term="WYSIWYG" /><category term="gwt-math" /><category term="BigDecimal" /><category term="AJAX" /><category term="XML" /><category term="RPC" /><category term="YUI" /><category term="Java" /><category term="GUI" /><category term="module" /><category term="Portlet" /><category term="socket" /><category term="Echo2" /><category term="Firefox" /><category term="Eclipse" /><category term="HTML" /><category term="IE" /><category term="JDOM" /><category term="JSF" /><category term="framework" /><category term="parser" /><category term="JavaScript" /><category term="internacjonalizacja" /><title type="text">coder's life</title><subtitle type="html">&lt;em&gt;Imagination is more important than knowledge&lt;/em&gt; Albert Einstein</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/CodersLife" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="coderslife" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-6456155445524437860</id><published>2008-05-05T16:39:00.007+02:00</published><updated>2008-05-05T17:12:08.218+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="double" /><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="BigDecimal" /><category scheme="http://www.blogger.com/atom/ns#" term="gwt-math" /><title type="text">BigDecimal w GWT</title><content type="html">Zawsze gdy testujemy jakiś framework wybieramy najprostszą drogę, co między innymi oznacza, iż korzystamy z takich typów danych jak: &lt;code&gt;String&lt;/code&gt; i &lt;code&gt;Integer&lt;/code&gt;. Niemniej jednak przychodzi czas kiedy musimy zmierzyć się z obsługą co najmniej kilku typów danych m.in. z typem zmiennoprzecinkowym. Doświadczenie nauczyło mnie, że jeżeli chodzi o Javę to najlepszym typem zmiennoprzecinkowym do wykonywania operacji arytmetycznych jest &lt;code&gt;BigDecimal&lt;/code&gt;. Pewnie co niektórym nasuwa się pytanie - dlaczego nie &lt;code&gt;double&lt;/code&gt;. Moją odpowiedzią będzie przykład zaczerpniety ze strony &lt;a href="http://epramono.blogspot.com/2005/01/double-vs-bigdecimal.html"&gt;http://epramono.blogspot.com&lt;/a&gt;:&lt;code&gt;&lt;pre&gt;public static void main (String[] args) {&lt;br /&gt;  System.out.println (&lt;br /&gt;    "(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1) = " +&lt;br /&gt;    (0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1));&lt;br /&gt;&lt;br /&gt;  double d = 0.0;&lt;br /&gt;  while (d &lt;= 1.0) d += 0.1;&lt;br /&gt;  System.out.println ("d = " + d);&lt;br /&gt;&lt;br /&gt;  System.out.println ("0.0175 * 100000 = " + 0.0175 * 100000);&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;Wynik na wyjściu:&lt;code&gt;&lt;pre&gt;(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1) = 0.9999999999999999&lt;br /&gt;d = 1.0999999999999999&lt;br /&gt;0.0175 * 100000 = 1750.0000000000002&lt;/pre&gt;&lt;/code&gt;Upss... co za niemiła niespodzianka :(&lt;br /&gt;&lt;br /&gt;Nie o tym jednak zamierzam pisać moim głównym tematem jest GWT (wersja 1.4.60), a w zasadzie obsługa typu &lt;code&gt;BigDecimal&lt;/code&gt; w GWT, której najogólniej rzecz ujmując po prostu nie ma. To oczywiście poważny problem... ale jest na to rozwiązanie:&lt;ul&gt;&lt;li&gt;Wchodzimy na stronę: &lt;a href="http://code.google.com/p/gwt-math/"&gt;http://code.google.com/p/gwt-math/&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Ściągamy dwie biblioteki &lt;code&gt;gwt-math-2.0.1.jar&lt;/code&gt;, &lt;code&gt;gwt-math-server-2.0.1.jar&lt;/code&gt; i umieszczamy je w &lt;code&gt;classpath&lt;/code&gt; naszego projektu.&lt;/li&gt;&lt;li&gt;W pliku &lt;code&gt;MyModule.gwt.xml&lt;/code&gt; dodajemy sekcję:&lt;code&gt;&lt;pre&gt;&amp;lt;inherits name="com.googlecode.gwt.math.Math"/&amp;gt;&lt;/pre&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Na tym koniec naszej pracy, możemy korzystać już z klas &lt;code&gt;java.math.BigDecimal&lt;/code&gt;, &lt;code&gt;java.math.BigInteger&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Reasumując: często jest tak, gdy sytuacja wydaje się być beznadziena z pomocą przychodzi &lt;em&gt;Google&lt;/em&gt;, poprzez które odkrywamy, że społeczność &lt;em&gt;Open Source&lt;/em&gt; przewidziała, że możemy natknąć się na dany problem. Stąd lepiej najpierw poszukać, niż zrobić po swojemu :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-6456155445524437860?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/6456155445524437860/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=6456155445524437860" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/6456155445524437860" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/6456155445524437860" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2008/05/bigdecimal-w-gwt.html" title="BigDecimal w GWT" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-226150379478017524</id><published>2008-04-25T22:13:00.010+02:00</published><updated>2008-04-26T22:51:26.537+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="internacjonalizacja" /><title type="text">GWT - internacjonalizacja</title><content type="html">&lt;p&gt;Jeżeli docelową grupą użytkowników naszej aplikacji są ludzie o różnych narodowościach wówczas warto dostosować ją do obsługi wielu języków. Pierwszą rzeczą z którą przyjdzie się nam zmierzyć będzie tłumaczenie tekstów stałych. Samo tłumaczenie tekstów możemy pozostawić lingwistom, natomiast naszym zadaniem jest napisanie tak aplikacji, aby obsługa tych tekstów była możliwa i przy dodawaniu kolejnych tłumaczeń nie wymagała pracy programistycznej.&lt;br /&gt;&lt;br /&gt;Oczywiście każdy programista dość szybko poradziłby sobie z tym zagadnieniem wymyślając swój własny mechanizm, ale programista &lt;em&gt;leniwy&lt;/em&gt; (czytaj: &lt;em&gt;skuteczny&lt;/em&gt;) przegrzebie dokumentację w celu znalezieniu mechanizmu, który już został wymyślony. Jak to wygląda w GWT...&lt;/p&gt;&lt;p&gt;Podstawowym elementem, który umożliwi nam lokalizację tekstów stałych jest moduł zawarty w pakiecie &lt;code&gt;com.google.gwt.i18n&lt;/code&gt; oferuje on kilka mechanizmów: &lt;code&gt;Constants&lt;/code&gt;, &lt;code&gt;Messages&lt;/code&gt;, &lt;code&gt;ConstantsWithLookup&lt;/code&gt;, &lt;code&gt;Dictionary&lt;/code&gt;, &lt;code&gt;Localizable&lt;/code&gt;. Skoncentrujmy się jednak na dwóch podstawowych &lt;code&gt;Constants&lt;/code&gt; i &lt;code&gt;Messages&lt;/code&gt;, które powinny być używane w większości przypadków.&lt;br /&gt;&lt;br /&gt;Jeżeli chcemy skorzystać z tych mechanizmów nasz moduł musi dziedziczyć po module &lt;code&gt;com.google.gwt.i18n.I18N&lt;/code&gt; (plik &lt;code&gt;MyModule.gwt.xml&lt;/code&gt; w pakiecie &lt;code&gt;com.mycompany.mymodule&lt;/code&gt;):&lt;pre&gt;&lt;code&gt;&amp;lt;module&amp;gt;&lt;br /&gt;  &amp;lt;inherits name="com.google.gwt.i18n.I18N"/&amp;gt;&lt;br /&gt;&amp;lt;/module&amp;gt;&lt;br /&gt;&amp;lt;extend-property name="locale" values="pl,en"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;Kolejnym krokiem jest stworzenie plików zawierających teksty stałe dla poszczególnych języków oraz plik domyślny.&lt;br /&gt;&lt;br /&gt;Plik domyślny &lt;code&gt;MyConstans.properties&lt;/code&gt; (w pakiecie &lt;code&gt;com.mycompany.mymodule.client&lt;/code&gt;):&lt;pre&gt;&lt;code&gt;helloWorld = Witaj Świecie&lt;br /&gt;goodbyeWorld = Do widzenia Świecie&lt;/code&gt;&lt;/pre&gt;Plik dla języka polskiego &lt;code&gt;MyConstans_pl.properties&lt;/code&gt; (w pakiecie &lt;code&gt;com.mycompany.mymodule.client&lt;/code&gt;):&lt;pre&gt;&lt;code&gt;helloWorld = Witaj Świecie&lt;br /&gt;goodbyeWorld = Do widzenia Świecie&lt;/code&gt;&lt;/pre&gt;Plik dla języka angielskiego &lt;code&gt;MyConstans_en.properties&lt;/code&gt; (w pakiecie &lt;code&gt;com.mycompany.mymodule.client&lt;/code&gt;):&lt;pre&gt;&lt;code&gt;helloWorld = Hello World&lt;br /&gt;goodbyeWorld = Goodbye World&lt;/code&gt;&lt;/pre&gt;Kolejnym krokiem jest stworznie w pakiecie &lt;code&gt;com.mycompany.mymodule.client&lt;/code&gt; interfejsu &lt;code&gt;MyConstans&lt;/code&gt;, w którym nazwy metod będą odpowiadać kluczom w plikach z tekstami stałymi:&lt;pre&gt;&lt;code&gt;public interface MyConstants extends Constants {&lt;br /&gt;  String helloWorld();&lt;br /&gt;  String goodbyeWorld();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Aby użyć nasze teksty wystarczą dwie linie kodu w kodzie klasy klienta (np. &lt;code&gt;MyModule.java&lt;/code&gt;):&lt;pre&gt;&lt;code&gt;  MyConstants myConstants = (MyConstants)GWT.create(MyConstants.class);&lt;br /&gt;  Window.alert(myConstants.helloWorld());&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Drugi mechanizm, który niejako stawi rozszerzenie &lt;code&gt;Constants&lt;/code&gt; to &lt;code&gt;Messages&lt;/code&gt;, różni się on jedynie tym, iż teksty stałe mogą posiadać argumenty. Załóżmy, iż w pliku &lt;code&gt;ErrorMessages.properties&lt;/code&gt; mamy tekst:&lt;pre&gt;&lt;code&gt;permissionDenied = Błąd {0}: Użytkownik {1} nie ma uprawnień dostęp do {2}&lt;/code&gt;&lt;/pre&gt;Wóczas definiujemy interfejs analogiczny do &lt;code&gt;Constants&lt;/code&gt; przy czym metody powinny mieć tyle argumentów wejściowych ile zostało wymienonych w tekstach stałych. Definicja interfejsu &lt;code&gt;ErrorMessages.java&lt;/code&gt;:&lt;pre&gt;&lt;code&gt;public interface ErrorMessages extends Messages {&lt;br /&gt;  String permissionDenied(int errorCode, String username, String resource);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Aby teksty stałe były wyświetlane w danym języku mamy dwie możliwości. Pierwsza polega na ustawieniu właściwości &lt;code&gt;&amp;lt;meta name="gwt:property" content="locale=pl"&amp;gt;&lt;/code&gt; bezpośrednio w stronie html:&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;  &amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;meta name="gwt:module" content="com.mycompany.mymodule.MyModule"&amp;gt;&lt;br /&gt;    &amp;lt;meta name="gwt:property" content="locale=pl"&amp;gt;&lt;br /&gt;  &amp;lt;/head&amp;gt;&lt;br /&gt;  &amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;script src="gwt.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;  &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;Druga możliwość to dodanie parametru do URL:&lt;pre&gt;&lt;code&gt;http://www.mycompany.com/MyModule.html?locale=pl&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Mechanizmy, ktore zostały opisane można używać tylko w kodzie na podstawie, którego jest generowany JavaScript (czyli który jest umieszczony w pakiecie &lt;code&gt;client&lt;/code&gt;). Podczas kompilacji GWT wytwarza dla każdej lokalizacji odrębny plik JavaScript.&lt;/p&gt;&lt;p&gt;Reasumując GWT dostarcza dość kompleksowy mechanizm internacjonalizacji, choć według mnie wystarczyłby mechanizm &lt;code&gt;Messages&lt;/code&gt;, bo przecież nie mogę od razu przewidzieć, że mój tekst stały nie będzie miał kiedyś argumentów. Kolejną rzeczą, która stanowi dla mnie pewną wadę jest to, iż nie można używać tych mechanizmów po stronie serwera, co zmusza nas do korzystania ze standardowego rozwiązania dostarczonego przez Java &lt;code&gt;ResourceBundle&lt;/code&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-226150379478017524?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/226150379478017524/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=226150379478017524" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/226150379478017524" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/226150379478017524" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2008/04/gwt-co-nacja-to-inna.html" title="GWT - internacjonalizacja" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-1648535269785948834</id><published>2008-01-21T20:26:00.007+01:00</published><updated>2008-05-04T17:18:13.459+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><title type="text">Równy czy nierówny - oto jest pytanie</title><content type="html">Ktoś kiedyś powiedział "mnie język w programowaniu nie przeszkadza"? Co mnie więcej oznacza, iż doświadczony programista, który miał do czynienia z kilkoma językami (np. C, Java) bez problemu powinien poradzić sobie z programowaniem w kolejnym języku (np. w C#). Jest w tym wiele prawdy, ale czy bez kompleksowej wiedzy z danego języka kod owego programisty będzie na pewno niezawodny?&lt;br /&gt;&lt;br /&gt;Rozważmy prosty przykład napisany w języku Java:&lt;pre&gt;&lt;code&gt;Integer i1 = 1000;&lt;br /&gt;Integer i2 = 1000;&lt;br /&gt;if (i1 == i2) {&lt;br /&gt; System.out.println("ten sam obiekt");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt; System.out.println("rozne obiekty");&lt;br /&gt;}&lt;br /&gt;if (i1.equals(i2)) {&lt;br /&gt; System.out.println("wartosci obiektow sa takie same");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt; System.out.println("wartosci obiektow nie sa takie same");&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Czy jest coś w tym przykładzie co mogłoby nas skłonić do refleksji - raczej nie. Oczywiste wydaje się, iż w pierwszym warunku zostanie wyświetlone na konsoli &lt;code&gt;"rozne obiekty"&lt;/code&gt;, natomiast w drugim warunku &lt;code&gt;"rowne obiekty"&lt;/code&gt;. Pierwszy warunek będzie spełniony tylko wtedy gdy będziemy mieli do czynienia ze zmiennymi, które wskazują dokładnie na ten sam obiekt. Drugi warunek to już porównanie wartości tych obiektów więc sprawa jest dość oczywista.&lt;br /&gt;&lt;br /&gt;Zmodyfikujmy ten przykład:&lt;pre&gt;&lt;code&gt;Integer i1 = 10;&lt;br /&gt;Integer i2 = 10;&lt;br /&gt;if (i1 == i2) {&lt;br /&gt; System.out.println("ten sam obiekt");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt; System.out.println("rozne obiekty");&lt;br /&gt;}&lt;br /&gt;if (i1.equals(i2)) {&lt;br /&gt; System.out.println("wartosci obiektow sa takie same");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt; System.out.println("wartosci obiektow nie sa takie same");&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Co się okazuje? Pierwszy warunek jest spełniony w efekcie na konsoli zostanie wyświetlone &lt;code&gt;"ten sam obiekt"&lt;/code&gt;. Dlaczego? Odpowiedź jest prosta, chociaż nie oczywista: w języku Java w celu zaoszczędzenia pamięci instancje klas &lt;code&gt;Short&lt;/code&gt; and &lt;code&gt;Integer&lt;/code&gt; o wartościach od &lt;code&gt;-128&lt;/code&gt; do &lt;code&gt;127&lt;/code&gt; wskazują na ten sam obiekt (obszar pamięci). Inaczej się ma sytuacja jeżeli jawnie użyjemy operatora &lt;code&gt;new&lt;/code&gt;:&lt;pre&gt;&lt;code&gt;Integer i1 = new Integer(10);&lt;br /&gt;Integer i2 = new Integer(10);&lt;br /&gt;if (i1 == i2) {&lt;br /&gt; System.out.println("ten sam obiekt");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt; System.out.println("rozne obiekty");&lt;br /&gt;}&lt;br /&gt;if (i1.equals(i2)) {&lt;br /&gt; System.out.println("wartosci obiektow sa takie same");&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt; System.out.println("wartosci obiektow nie sa takie same");&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;Wówczas zostanie wyświetlone &lt;code&gt;"rozne obiekty"&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Wniosek z tego jest jeden, iż bez dogłębnej znajomości języka, konstrukcje, które mogłyby się wydawać oczywiste mogą nas zaskoczyć w najmniej oczekiwanym momencie. Jest na to jednak rada: jeżeli jesteś czegoś pewien sprawdź to, a jeżeli jesteś czegoś bardzo pewien sprawdź to dwa razy...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-1648535269785948834?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/1648535269785948834/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=1648535269785948834" title="Komentarze (4)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/1648535269785948834" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/1648535269785948834" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2008/01/rwny-czy-nierwny-oto-jest-pytanie.html" title="Równy czy nierówny - oto jest pytanie" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-4441703661817302080</id><published>2007-12-30T16:28:00.000+01:00</published><updated>2007-12-30T21:24:43.992+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><title type="text">Kreatory w GWT</title><content type="html">W dystrybucji GWT znajdują się cztery skrypty cmd, które w największym skrócie można nazwać kreatorami. Każdy z nich jest wykorzystywany na różnym etapie tworzenia aplikacji.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;projectCreator&lt;/strong&gt;&lt;br /&gt;GWT pozwala na łatwą integrację ze środowiskiem Eclipse, dlatego też jeżeli podczas tworzenia aplikacji programista zamierza korzystać z tego IDE, wówczas powinien użyć tego narzędzia. Kreator ten zakłada strukturę katalogów (wraz z plikami .project oraz .classpath) , która pozwoli łatwo zaimportować tworzoną aplikację jako projekt Eclipse.&lt;br /&gt;&lt;br /&gt;Wykonując komendę:&lt;pre&gt;&lt;code&gt;projectCreator -eclipse MyAppPrj -out MyAppDir&lt;/code&gt;&lt;/pre&gt;Utworzona zostanie następująca struktura:&lt;pre&gt;&lt;code&gt;Created directory MyAppDir\src&lt;br /&gt;Created directory MyAppDir\test&lt;br /&gt;Created file MyAppDir\.project&lt;br /&gt;Created file MyAppDir\.classpath&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;applicationCreator&lt;/strong&gt;&lt;br /&gt;Kreator ten pełni trzy funkcje:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Wytwarza strukturę pakietów dla aplikacji.&lt;/li&gt;&lt;li&gt;Generuje domyślne pliki HTML i Java spięte w prostym pliku module XML. Te pliki stanowią prostą aplikację od której można zacząć budowanie bardziej zaawansowanych funkcjonalności.&lt;/li&gt;&lt;li&gt;Tworzy skrypty cmd, które pozwalają przekompilować i uruchomić aplikację w trybie hosted mode.&lt;/li&gt;&lt;/ul&gt;Wykonując komendę (bez Eclipse):&lt;pre&gt;&lt;code&gt;applicationCreator -out MyAppDir com.example.client.MyApp&lt;/code&gt;&lt;/pre&gt;Wykonując komendę (z Eclipse):&lt;pre&gt;&lt;code&gt;applicationCreator -eclipse MyAppPrj -out MyAppDir com.example.client.MyApp&lt;/code&gt;&lt;/pre&gt;Utworzona zostanie następująca struktura:&lt;pre&gt;&lt;code&gt;Created directory MyAppDir\src\com\example&lt;br /&gt;Created directory MyAppDir\src\com\example\client&lt;br /&gt;Created directory MyAppDir\src\com\example\public&lt;br /&gt;Created file MyAppDir\src\com\example\MyApp.gwt.xml&lt;br /&gt;Created file MyAppDir\src\com\example\public\MyApp.html&lt;br /&gt;Created file MyAppDir\src\com\example\client\MyApp.java&lt;br /&gt;Created file MyAppDir\MyApp-shell.cmd&lt;br /&gt;Created file MyAppDir\MyApp-compile.cmd&lt;/code&gt;&lt;/pre&gt;W przypadku parametru -eclipse dodatkowo powstanie:&lt;pre&gt;&lt;code&gt;Created file MyAppDir\MyApp.launch&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;i18nCreator&lt;/strong&gt;&lt;br /&gt;Jeżeli pojawia się skrót i18n to oczywiście chodzi o internacjonalizację. Tym kreatorem wytwarzamy proste pliki properties zawierające teksty stałe w formie klucz/wartość.  Generowany jest również skrypt cmd [Appl]-i18n, który na podstawie plików properties generuje interfejs Java poprzez który mamy dostęp do tekstów stałych z kodu Java aplikacji GWT.&lt;br /&gt;&lt;br /&gt;Wykonując komendę (bez Eclipse):&lt;pre&gt;&lt;code&gt;i18nCreator -out MyAppDir com.example.client.MyAppConstants&lt;/code&gt;&lt;/pre&gt;Wykonując komendę (z Eclipse):&lt;pre&gt;&lt;code&gt;i18nCreator -eclipse MyAppPrj -out MyAppDir com.example.client.MyAppConstants&lt;/code&gt;&lt;/pre&gt;Utworzona zostanie następująca struktura:&lt;pre&gt;&lt;code&gt;Created file MyAppDir\src\com\example\client\MyAppConstants.properties&lt;br /&gt;Created file MyAppDir\MyAppConstants-i18n.cmd&lt;/code&gt;&lt;/pre&gt;W przypadku parametru -eclipse dodatkowo powstanie:&lt;pre&gt;&lt;code&gt;Created file MyAppDir\MyAppConstants-i18n.launch&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;jUnitCreator&lt;/strong&gt;&lt;br /&gt;Tworzy odpowiedni katalog oraz pliki, w którym należy umieścić testy jednostkowe aplikacji GWT.&lt;br /&gt;&lt;br /&gt;Wykonując komendę (bez Eclipse):&lt;pre&gt;&lt;code&gt;junitCreator -junit c:\junit.jar -module com.example.client.MyApp -out MyAppDir com.example.client.MyAppTest&lt;/code&gt;&lt;/pre&gt;Wykonując komendę (z Eclipse):&lt;pre&gt;&lt;code&gt;junitCreator -junit c:\junit.jar -eclipse MyAppPrj -module com.example.client.MyApp -out MyAppDir com.example.client.MyAppTest&lt;/code&gt;&lt;/pre&gt;Utworzona zostanie następująca struktura:&lt;pre&gt;&lt;code&gt;Created directory MyAppDir\test\com\example\client\test&lt;br /&gt;Created file MyAppDir\test\com\example\client\test\MyAppTest.java&lt;br /&gt;Created file MyAppDir\MyAppTest-hosted.cmd&lt;br /&gt;Created file MyAppDir\MyAppTest-web.cmd&lt;/code&gt;&lt;/pre&gt;W przypadku parametru -eclipse dodatkowo powstanie:&lt;pre&gt;&lt;code&gt;Created file MyAppDir\MyAppTest-hosted.launch&lt;br /&gt;Created file MyAppDir\MyAppTest-web.launch&lt;/code&gt;&lt;/pre&gt;Dzięki kreatorom można w ciągu dosłownie kilku chwil zbudować swoją pierwsza aplikację w GWT, dzięki czemu nawet niecierpliwi się nie zniechęcą. Oczywiście bardziej istotne jest to, że nie trzeba wykonywać powtarzalnych czynności, które może za nas wykonać automat.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-4441703661817302080?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/4441703661817302080/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=4441703661817302080" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/4441703661817302080" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/4441703661817302080" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/12/kreatory-w-gwt.html" title="Kreatory w GWT" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-7010196712032629834</id><published>2007-12-23T20:29:00.000+01:00</published><updated>2007-12-23T21:24:31.840+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="Echo2" /><title type="text">Dlaczego GWT jest lepsze od Echo2</title><content type="html">Pamiętam jak dawno dawno temu natrafiłem na bardzo ciekawy framework jakim był Echo2, sama koncepcja pisania dla mnie była genialna, ale jednak po dokładniejszej analizie tego rozwiązania stwierdziłem, iż w praktyce ma ona małe szanse powodzenia. Teraz nadeszedł moment, gdy postanowiłem porównać go z GWT, ponieważ sama idea pisania aplikacji w tych frameworkach jest analogiczna, ale zasada działania już zupełnie inna.&lt;br /&gt;&lt;br /&gt;Zarówno w GWT jak i w Echo2 programista używa API zbliżonego do Swinga (lub jak kto woli do AWT). Poniżej zamieszony został przykład jak dodać pole edycyjne i przycisk w Echo2:&lt;pre&gt;&lt;code&gt;final TextField text = new TextField();&lt;br /&gt;text.setText("Pusta wartosc");&lt;br /&gt;&lt;br /&gt;final Button button = new Button();&lt;br /&gt;button.setText("Uzupelnij");&lt;br /&gt;button.addActionListener(new ActionListener() {&lt;br /&gt;  public void actionPerformed(ActionEvent event) {&lt;br /&gt;    text.setText("Uzupelniona wartosc");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Window window = new Window();&lt;br /&gt;window.setContent(new ContentPane());&lt;br /&gt;window.getContent.add(text);&lt;br /&gt;window.getContent.add(button);&lt;/code&gt;&lt;/pre&gt;Natomiast w GWT ten sam przykład wygląda tak:&lt;pre&gt;&lt;code&gt;final TextBox text = new TextBox();&lt;br /&gt;text.setText("Pusta wartosc");&lt;br /&gt;&lt;br /&gt;final Button button = new Button();&lt;br /&gt;button.setText("Uzupelnij");&lt;br /&gt;button.addClickListener(new ClickListener() {&lt;br /&gt;  public void onClick(Widget sender) {&lt;br /&gt;    textField.setText("Uzupelniona wartosc");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;RootPanel.get().add(text);&lt;br /&gt;RootPanel.get().add(button);&lt;/code&gt;&lt;/pre&gt;Jeżeli chodzi o porównanie kodu nie ma zasadniczych różnic, natomiast w działaniu sytuacja jest odmienna.&lt;br /&gt;&lt;br /&gt;GWT na podstawie kodu Java generuje JavaScript, który jest uruchamiany w przeglądarce Internetowej, natomiast Echo2 kompiluje kod do klasy Java, a następnie uruchamia go na serwerze. To powoduje, iż każde zdarzenie (np. naciśnięcie przycisku) generuje ruch pomiędzy przeglądarką Internetową, a serwerem. Wybraźmy sobie co by było gdyby po każdym wyjściu z pola edycyjnego było uruchamiane zdarzenie (Echo2 ograniczyło na szczęście uruchamianie takich zdarzeń). Stąd podejście proponowane przez Echo2 zupełnie do mnie nie przemawia, bo generuje zbyt duży ruch w sieci. Oczywiście są pewne zalety takiego podejścia np. na serwerze wiadomo jaki jest stan aplikacji, jest wysyłany tylko niezbędny JavaScript.&lt;br /&gt;&lt;br /&gt;Twórcy GWT wybrali wg mnie bardziej naturalną drogę skoro interfejs jest w przeglądarce to i aplikacja jest w niej uruchamiana, a komunikuje się z serwerem tylko wtedy gdy jest to niezbędne.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-7010196712032629834?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/7010196712032629834/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=7010196712032629834" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7010196712032629834" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7010196712032629834" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/12/dlaczego-gwt-jest-lepsze-od-echo2.html" title="Dlaczego GWT jest lepsze od Echo2" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-2556464748503220108</id><published>2007-11-11T19:42:00.000+01:00</published><updated>2007-11-11T20:24:57.885+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="IE" /><category scheme="http://www.blogger.com/atom/ns#" term="HTML" /><category scheme="http://www.blogger.com/atom/ns#" term="hack" /><category scheme="http://www.blogger.com/atom/ns#" term="Firefox" /><title type="text">Html Hack dobry na wszystko</title><content type="html">Pamiętam czasy gdy programy pisało się korzystając z biblioteki curses, a interfejs użytkownika stanowił terminal 80x24. Nie będę się na ten temat zbytnio rozwodził, ale wspominam jedną rzecz jak coś napisałem to działało na każdym terminalu. Później przyszła era aplikacji GUI (np. Delphi, Swing), aż wreszcie doszliśmy do przeglądarek Internetowych i tutaj zaczeły się problemy. Na Firefoxie coś działa, a na Internet Explorze nie itd. W poprzednim tygodniu natrafiłem właśnie na taki problem i jak zawsze z pomocą przyszedł "html hack", czyli wykorzystanie słynnej funkcji JavaScript &lt;code&gt;setTimeout&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Zacznę od początku (tak chyba najlepiej) czyli od przykładu, który zobrazuje problem na który natrafiłem. Otóż chodziło o to aby przycisk po zaznaczeniu checkboxa się pokazywał (dodatkowo atrybut &lt;code&gt;position&lt;/code&gt; musiał być &lt;code&gt;relative&lt;/code&gt;), a po odznaczeniu chował (dodatkowo atrybut &lt;code&gt;position&lt;/code&gt; musiał być &lt;code&gt;absolute&lt;/code&gt;). Cały kod html zawarłem poniżej:&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;function changeDiv(checkboxEl) {&lt;br /&gt;  var divElStyle = document.getElementById("div1").style;&lt;br /&gt;  if (checkboxEl.checked) {&lt;br /&gt;    divElStyle.position = "relative";&lt;br /&gt;    divElStyle.visibility= "visible";&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    divElStyle.position = "absolute";&lt;br /&gt;    divElStyle.visibility= "hidden";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;//--&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;input type="checkbox" &lt;br /&gt;       onclick="changeDiv(this);"&amp;gt;Test&amp;lt;/input&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;br /&amp;gt;&lt;br /&gt;&lt;br /&gt;Poczatek&amp;nbsp;&lt;br /&gt;&amp;lt;div id="div1"&lt;br /&gt;     style="position: absolute; display: inline; visibility: hidden;"&amp;gt;&lt;br /&gt;  &amp;lt;input type="button" value="Test" /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;nbsp;Koniec&lt;br /&gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Po uruchomieniu tego przykładu okazało się, że owszem w Firefoxie działa wszystko jak należy, ale w Internet Explorerze przycisk jest niewidoczny, przy czym jest rezerwowane na niego miejsce.&lt;br /&gt;&lt;br /&gt;Oczywiście pełen pokory, ale i wiary w sukces zabrałem się do pracy, już po kilku chwilach stwierdziłem, że problem jest związany z przypisywaniem do atrybutu &lt;code&gt;position&lt;/code&gt; wartości &lt;code&gt;relative&lt;/code&gt;. Niestety Internet Explorer z tym sobie nie radzi. Problem znaleziony, więc przeszedłem do rozwiązania, które sprowadziło się do pragmatycznego posunięcia jakim było zastosowanie funkcji &lt;code&gt;setTimeout&lt;/code&gt; - popularnego i "lubianego" html hacku.&lt;br /&gt;&lt;br /&gt;Poniżej zamieszczam zmodyfikowany kod, który działa w Internet Explorerze:&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;function changeDiv(checkboxEl) {&lt;br /&gt;  var divElStyle = document.getElementById("div1").style;&lt;br /&gt;  if (checkboxEl.checked) {&lt;br /&gt;    divElStyle.position = "relative";&lt;br /&gt;    setTimeout(&lt;br /&gt;      'document.getElementById("div1").style.visibility = "visible"',&lt;br /&gt;      1);&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    divElStyle.position = "absolute";&lt;br /&gt;    divElStyle.visibility= "hidden";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;//--&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;input type="checkbox" &lt;br /&gt;       onclick="changeDiv(this);"&amp;gt;Test&amp;lt;/input&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;br /&amp;gt;&lt;br /&gt;&lt;br /&gt;Poczatek&amp;nbsp;&lt;br /&gt;&amp;lt;div id="div1"&lt;br /&gt;     style="position: absolute; display: inline; visibility: hidden;"&amp;gt;&lt;br /&gt;  &amp;lt;input type="button" value="Test" /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;nbsp;Koniec&lt;br /&gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;Zachęcam Was do podzielania się swoimi ciekawymi doświadczeniami.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-2556464748503220108?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/2556464748503220108/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=2556464748503220108" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/2556464748503220108" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/2556464748503220108" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/11/html-hack-dobry-na-wszystko.html" title="Html Hack dobry na wszystko" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-8374253757149781736</id><published>2007-11-03T18:22:00.000+01:00</published><updated>2007-11-03T18:32:21.863+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="funny" /><title type="text">Spotkaj swojego idola - James Gosling</title><content type="html">Chyba nikomu nie trzeba przybliżać osoby Jamesa Goslinga. Ze względu na weekend zamieszczam link do krótkiego filmu, którego jest on głównym bohaterem. Przyznam, że film mnie bardzo rozbawił: &lt;a href="http://www.javapolis.com/JP06/campaign/index.php?ID=53&amp;amp;PWD=342a7c479017e16647acb399b90a27b6"&gt;There are better ways to meet your idols&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-8374253757149781736?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/8374253757149781736/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=8374253757149781736" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/8374253757149781736" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/8374253757149781736" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/11/ot-spotkaj-swojego-idola-james-gosling.html" title="Spotkaj swojego idola - James Gosling" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-7134979960112391002</id><published>2007-10-26T11:43:00.000+02:00</published><updated>2007-10-26T13:29:19.543+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="RPC" /><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="entry-point" /><category scheme="http://www.blogger.com/atom/ns#" term="Eclipse" /><category scheme="http://www.blogger.com/atom/ns#" term="module" /><title type="text">GWT - module czy entry-point</title><content type="html">W programowaniu często jest tak, że zrobienie podstawowej rzeczy jest proste i szybkie, dotyczy to w szczególności frameworków. W dystrybucji danej biblioteki mamy często mnóstwo przykładów, które charakteryzują się jednym elementem - są proste, niekiedy zbyt proste. Podobnie zresztą jest z większością tutoriali. Jednak czy jest to problem. Na początku nie, ale później owszem. Bo co z tego, że po zapoznaniu się z przykładami, czy kursami potrafimy zrobić jeden formularz skoro nie wiemy jak zaprojektować, a później zaprogramować całą aplikację. Oczywiście intuicja podpowiada programiście, w którym kierunku należy podążać, jednak zawsze zadaje sobie on pytanie czy jest to kierunek słuszny, zgodny ze sztuką i czy architektura jego aplikacji jest optymalna.&lt;br /&gt;&lt;br /&gt;Właśnie na taki problem napotkałem tworząc aplikację w GWT. Moja aplikacja składać się miała z dwóch elementów: panelu dla użytkownika oraz panelu dla administratora. Jednak pewne elementy tych paneli miały być wspólne: zarówno elementy ekranu jak np. DialogBox, jak również serwisy RPC. Więc oto stanąłem przed dylematem, jak to rozwiązać w GWT - czy stworzyć jeden moduł z kilkoma elementami entry-point, czy kilka modułów. Na początku byłem skłonny tworzyć kilka entry-pointów, do czasu gdy uprzytomniłem sobie, iż moduły mogą po sobie dziedziczyć. Wówczas było już z górki, postanowiłem stowrzyć jeden moduł ogólny, w którym umieściłem wspólny kod dla obu paneli, oraz dwa moduły zawierające specyficzny kod, jeden dla panelu administratora, a drugi dla panelu użytkownika. Oczywiście te dwa moduły dziedziczyły po module ogólnym. Wszystko było w obrębie jednego projektu Eclipse.&lt;br /&gt;&lt;br /&gt;Teraz przedstawie to od strony technicznej.&lt;br /&gt;W pierwszej kolejności tworzymy moduł ogólny, który będzie wyglądał następująco:&lt;br /&gt;&lt;br /&gt;Pakiety:&lt;pre&gt;&lt;code&gt;com.blogspot.coderlife.app.common&lt;br /&gt;com.blogspot.coderlife.app.common.client&lt;br /&gt;com.blogspot.coderlife.app.common.server&lt;br /&gt;com.blogspot.coderlife.app.common.public&lt;/code&gt;&lt;/pre&gt;Zawartość pakietów:&lt;pre&gt;&lt;code&gt;com.blogspot.coderlife.app.common&lt;br /&gt;  Common.gwt.xml&lt;br /&gt;&lt;br /&gt;com.blogspot.coderlife.app.common.client&lt;br /&gt;  CommonService.java&lt;br /&gt;  CommonServiceAsync.java&lt;br /&gt;  CommonDialogBox.java&lt;br /&gt;&lt;br /&gt;com.blogspot.coderlife.app.common.server&lt;br /&gt;  CommonServiceImpl.java&lt;br /&gt;&lt;br /&gt;com.blogspot.coderlife.app.common.public&lt;br /&gt;  (Pusty)&lt;/code&gt;&lt;/pre&gt;Zawartość pliku Common.gwt.xml:&lt;pre&gt;&lt;code&gt;&amp;lt;module&amp;gt;&lt;br /&gt;&amp;lt;inherits name="com.google.gwt.user.User"&amp;gt;&lt;br /&gt;&amp;lt;servlet &lt;br /&gt;  class="com.blogspot.coderlife.app.common.server.CommonServiceImpl" &lt;br /&gt;  path="/commonService"&amp;gt;&lt;br /&gt;&amp;lt;/module&amp;gt;&lt;/code&gt;&lt;/pre&gt;Należy zwrócić uwage na to, iż ten moduł nie zawiera żadnego elementu entry-point, ponieważ będzie on przechowywał wszystkie elementy wspólne, a sam nie będzie uruchamiany, stąd też pakiet com.blogspot.coderlife.app.common.public jest pusty nie zawiera żadnej strony html.&lt;br /&gt;&lt;br /&gt;W drugim kroku tworzymy moduł administratora, który będzie wyglądał następująco:&lt;br /&gt;&lt;br /&gt;Pakiety:&lt;pre&gt;&lt;code&gt;com.blogspot.coderlife.app.adminpanel&lt;br /&gt;com.blogspot.coderlife.app.adminpanel.client&lt;br /&gt;com.blogspot.coderlife.app.adminpanel.server&lt;br /&gt;com.blogspot.coderlife.app.adminpanel.public&lt;/code&gt;&lt;/pre&gt;Zawartość pakietów:&lt;pre&gt;&lt;code&gt;com.blogspot.coderlife.app.adminpanel&lt;br /&gt;  AdminPanel.gwt.xml&lt;br /&gt;&lt;br /&gt;com.blogspot.coderlife.app.adminpanel.client&lt;br /&gt;  AdminPanel.java&lt;br /&gt;&lt;br /&gt;com.blogspot.coderlife.app.adminpanel.server&lt;br /&gt;  (Pusty)&lt;br /&gt;&lt;br /&gt;com.blogspot.coderlife.app.adminpanel.public&lt;br /&gt;  AdminPanel.html&lt;br /&gt;  AdminPanel.css&lt;/code&gt;&lt;/pre&gt;Zawartość pliku AdminPanel.gwt.xml:&lt;pre&gt;&lt;code&gt;&amp;lt;module&amp;gt;&lt;br /&gt;&amp;lt;inherits name="com.google.gwt.user.User"&amp;gt;&lt;br /&gt;&amp;lt;inherits name="com.blogspot.coderlife.app.common.server.Common"&amp;gt;&lt;br /&gt;&amp;lt;entry-point &lt;br /&gt;  class="com.blogspot.coderlife.app.adminpanel.client.AdminPanel"&amp;gt;&lt;br /&gt;&amp;lt;/module&amp;gt;&lt;/code&gt;&lt;/pre&gt;Ten moduł już będzie uruchamiany poprzez plik AdminPanel.html stąd zawiera on entry-point. Najbardziej istotne jest dziedziczenie tutaj po module Common.&lt;br /&gt;&lt;br /&gt;Nie będę zamieszczał zawartości UserPanel ponieważ jest analogiczna do AdminPanel.&lt;br /&gt;&lt;br /&gt;Reasumując wg mnie jeżeli aplikacja ma dwa niezależne panele (ekrany) powinno stworzyć się dwa moduły dla każdego z nich, natomiast wspólne elementy umieścić w trzecim wspólnym module (nie zawierającym żadnego entry-pointa).&lt;br /&gt;&lt;br /&gt;Zachęcam Was do podzielenia się opiniami co do prawidłowego modelu tworzenia aplikacji w GWT.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-7134979960112391002?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/7134979960112391002/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=7134979960112391002" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7134979960112391002" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7134979960112391002" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/10/gwt-module-czy-entry-point.html" title="GWT - module czy entry-point" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-4632600114406621081</id><published>2007-10-20T18:30:00.000+02:00</published><updated>2007-10-20T19:44:06.341+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="parser" /><category scheme="http://www.blogger.com/atom/ns#" term="socket" /><category scheme="http://www.blogger.com/atom/ns#" term="XML" /><category scheme="http://www.blogger.com/atom/ns#" term="JDOM" /><title type="text">Parsowanie XML przekazanego przez sockety</title><content type="html">Zacznę od przedstawienia problemu, który oczywiście nie istnieje dopóki się go nie napotka :) Problem tkwi w tym, iż część parserów XML zamyka wejściowy strumień (&lt;code&gt;InputStream&lt;/code&gt;) kiedy napotka EOF (-1). Dotyczy to choćby Xercesa, który jest domyślnym parserem dla biblioteki JDOM. Oczywiście nie byłoby w tym nic złego gdyby wejściowym strumieniem nie był &lt;code&gt;SocketInputStream&lt;/code&gt;, ponieważ jego zamknięcie powoduje jeden niekoniecznie pożądany skutek, a mianowicie zamknięcie socketu, który w efekcie jest już bezużyteczny co oznacza nic innego jak to, iż nie można przez niego wysłać odpowiedzi.&lt;br /&gt;&lt;br /&gt;W przypadku dużej części aplikacji sockety są wykorzystywane do realizacji klasycznego modelu żądanie-odpowiedź np. klient wysyła do serwera dokument XML, serwer go przetwarza, a następnie odpowiada klientowi innym dokumentem XML. Jednak w przypadku gdy po wczytaniu dokumentu XML przez serwer socket zostanie zamknięty, klientowi nie zostanie udzielona odpowiedź.&lt;br /&gt;&lt;br /&gt;Co można w takim razie zrobić aby osiągnąć pożądany efekt? Rozwiązania są dwa przy czym drugie z nich można zrealizować na kilka sposobów. Pierwsze rozwiązanie to opakowanie &lt;code&gt;InputStream&lt;/code&gt; (z socketu) w taki sposób aby nie zamykał on połączenia, czyli przesłonięcie metody &lt;code&gt;close()&lt;/code&gt;. Drugie rozwiązanie to przeczytanie wszystkiego do bufora, a następnie przekazanie jego zawartości do parsera XML. Przy czym co zrobić jeżeli wejściowy strumień danych jest duży i nie chcemy niepotrzebnie czekać aż zostanie cały wczytany i dopiero wówczas przekażemy go do parsera. Przecież przychodzące bajty mogą być przetwarzane przez parser XML zanim przyjdą kolejne.&lt;br /&gt;&lt;br /&gt;Jak to zrobić w takim razie efektywnie:&lt;pre&gt;&lt;code&gt;BufferedInputStream clientSocketInputStream =&lt;br /&gt;  new BufferedInputStream(clientSocket.getInputStream());&lt;/code&gt;&lt;/pre&gt;Zestawiamy ze sobą dwa strumienie typu piped:&lt;pre&gt;&lt;code&gt;PipedOutputStream pipedOutputStream = new PipedOutputStream();&lt;br /&gt;pipedInputStream = new PipedInputStream();&lt;br /&gt;pipedOutputStream.connect(pipedInputStream);&lt;/code&gt;&lt;/pre&gt;Tworzymy wątek łączący strumień wyjściowy piped ze strumieniem wejściowym socketu. Jego zadaniem jest czytanie danych z &lt;code&gt;clientSocketInputStream&lt;/code&gt; do &lt;code&gt;pipedOutputStream&lt;/code&gt;, który jest połączony z &lt;code&gt;pipedInputStream&lt;/code&gt;, który możemy bezpośrednio przekazać do parsera XML:&lt;pre&gt;&lt;code&gt;Output2InputThread output2InputThread =&lt;br /&gt;new Output2InputThread(pipedOutputStream, clientSocketInputStream);&lt;br /&gt;output2InputThread.start();&lt;br /&gt;SAXBuilder builder = new SAXBuilder();&lt;br /&gt;Document inputDocument = builder.build(pipedInputStream);&lt;/code&gt;&lt;/pre&gt;Implementacji klasy &lt;code&gt;Output2InputThread&lt;/code&gt; nie będę zamieszczał w całości, natomiast zamieszczę fragmenty, które pozwolą zorientować się co powinno się w niej znaleźć:&lt;pre&gt;&lt;code&gt;private static final int BUF_SIZE = 4096;&lt;br /&gt;byte[] buf = new byte[BUF_SIZE];&lt;br /&gt;&lt;br /&gt;public void run() {&lt;br /&gt;  int readedCount;&lt;br /&gt;  while (true) {&lt;br /&gt;    // Wczytuje z socketu do bufora&lt;br /&gt;    readedCount = clientSocketInputStream.read(buf);&lt;br /&gt;&lt;br /&gt;    // TODO Trzeba dodać jeszcze kod,&lt;br /&gt;    // TODO który sprawdzi kiedy należy przestać czytać&lt;br /&gt;&lt;br /&gt;    // Zapisuje bufor do pipedOutputStream&lt;br /&gt;    pipedOutputStream.write(buf, 0, readedCount);&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Nie zamieściłem kodu, który sprawdzi kiedy należy przestać czytać, ale takie coś już każdy może zrealizować samodzielnie. Wcześniej oczywiście trzeba ustalić sposób informowania o zakończeniu przesyłania dokumentu XML, można to zrobić np. poprzez przesłanie przed dokumentem nagłówka z ilością bajtów, które należy wczytać lub na końcu dokumentu jakiegoś umownego znacznika. Zwracam też uwagę, że ustalenie rozmiaru bufora na określoną wartość wcale nie oznacza, że podaczas jednej iteracji zostanie on cały zapełniony, w szczególnym przypadku może zostać wczytany tylko jeden bajt.&lt;br /&gt;&lt;br /&gt;Zachęcam Was do podzielenia się swoimi sposobami na rozwiązanie przedstawionego przeze mnie problemu.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-4632600114406621081?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/4632600114406621081/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=4632600114406621081" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/4632600114406621081" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/4632600114406621081" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/10/parsowanie-xml-przekazanego-przez.html" title="Parsowanie XML przekazanego przez sockety" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-7161112324387113582</id><published>2007-10-18T16:22:00.000+02:00</published><updated>2007-10-18T17:19:24.117+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="Designer" /><category scheme="http://www.blogger.com/atom/ns#" term="GUI" /><category scheme="http://www.blogger.com/atom/ns#" term="WYSIWYG" /><title type="text">GWT WYSIWYG powrót do korzeni</title><content type="html">Komu się nie zdarzyło czegoś skrobnąć w Swingu i/lub Delphi z wykorzystaniem graficznego designera, pewnie większości programistów. Owszem może kod który powstaje dzięki takiemu narzędziu nie jest najwyższych lotów, ale przynajmniej taki interfejs graficzny tworzy się po prostu szybko, nawet nie będąc ekspertem w zakresie danej biblioteki, koncentrujemy się tylko nad obsługą poszczególnych zdarzeń (np. onClick itd). No tak ale co z tego jak dzisiaj każdy (no może prawie każdy) oczekuje, że aplikacja będzie dostępna przez przeglądarkę Internetową i oczywiście aplety odpadają bo trzeba instalować JRE itd.&lt;br /&gt;&lt;br /&gt;Pamiętam historię, którą opowiedział mi mój znajomy o firmie w której programiści kilka lat temu tworzyli aplikację w Visual Basicu, a teraz robią to w JSP. Zapytałem czy są zadowoleni, a on odpowiedział, że nie do końca, ponieważ nie potrafią zrozumieć dlaczego, coś co tworzyli przez jeden dzień zajmuje im teraz trzy dni... Ta krótka opowieść zalatuję nostalgią za korzeniami, za środowiskami designerskimi typu WYSIWYG, w których interfejs użytkownika wyklikujemy, a oprogramowujemy tylko zdarzenia. Czy aby MVC było tym na co czekali programiści z opowieści... otóż nie.&lt;br /&gt;&lt;br /&gt;Czekali na GWT Designera narzędzie, które pozwala programować w taki sposób jakbyśmy to robili w Swingu, różnica jest tylko jedna efektem naszego klikania jest interfejs webowy.&lt;br /&gt;&lt;br /&gt;GWT Designer to kreator GUI, który wspiera również GWT. Posiada on zarówno możliwość wizualnego tworzenia interfejsu (WYSIWYG) jak i zestaw kreatorów, które generują za nas kod Java. Żeby stworzyć sam interfejs żytkownika nie trzeba pisać nawet jednej linijki kodu, tylko oprogramować zdarzenia. Chociaż jeżeli mamy ochotę wówczas oczywiście taki kod możemy sami zedytować, po czym ponownie przełączyć się do trybu wizualizacji. Wręcz w fantastyczny sposób jest wsparta internacjonalizacja - bez kompilacji po wyborze z listy rozwijanej języka możemy kontrolować jak będzie wyglądał nasz interfejs w różnych lokalizacjach.&lt;br /&gt;&lt;br /&gt;Korzystając z WYSWIG możemy:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;dodawać kontrolki techniką drag&amp;amp;drop,&lt;/li&gt;&lt;li&gt;dodawać obsługę zdarzeń poprzez kliknięcie w kontrolkę,&lt;/li&gt;&lt;li&gt;zmieniać właściwości kontrolki poprzez użycie palety edytora właściwości,&lt;/li&gt;&lt;li&gt;zmieniać i wykonywać refactoring wygenerowanego kodu, efekty natychmiast są widoczne w edytorze wizualnym,&lt;/li&gt;&lt;li&gt;narzędzi radzi sobie również z kodem, który został napisany ręcznie, potrafi go przeanalizować i zaprezentować w wizualnym narzędziu,&lt;/li&gt;&lt;li&gt;a co najważniejsze sam GWT Designer jest niczym innym jak pluginem do Eclipse,&lt;/li&gt;&lt;li&gt;największą jego wadą jest to że nie jest darmowy.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Najszybciej możecie zapoznać się z jego możliwościami poprzez filmiki demo dostępne pod adresem: &lt;a href="http://www.instantiations.com/gwtdesigner/demos.html"&gt;http://www.instantiations.com/gwtdesigner/demos.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Źródło: &lt;a href="http://www.instantiations.com/gwtdesigner/index.html"&gt;http://www.instantiations.com/gwtdesigner/index.html&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-7161112324387113582?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/7161112324387113582/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=7161112324387113582" title="Komentarze (1)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7161112324387113582" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7161112324387113582" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/10/gwt-powrt-do-korzeni.html" title="GWT WYSIWYG powrót do korzeni" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-1645030050758663560</id><published>2007-10-17T20:33:00.000+02:00</published><updated>2007-10-18T08:10:00.170+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="YUI" /><category scheme="http://www.blogger.com/atom/ns#" term="framework" /><category scheme="http://www.blogger.com/atom/ns#" term="HTML" /><title type="text">YUI rywal GWT?</title><content type="html">Google udostępniło programistom &lt;b&gt;Google Web Toolkit&lt;/b&gt; (GWT), framework do szybkiego i przyjemnego tworzenia aplikacji webowych. Oczywiście słowo "przyjemnego" jest kwestią względną, ale na pewno tak mógłby powiedzieć programista Java, który stroni od JavaScriptu i HTMLa. Dlaczego? Bo w GWT nie musi stosować żadnego innego języka poza Javą. Ale czy to jest właśnie kierunek rozwoju frameworków webowych, który okaże się tym najwłaściwszym. W tym momencie ciężko przesądzić.&lt;br /&gt;&lt;br /&gt;Zupełnie inną koncepcję proponuje Yahoo - tak, tak Yahoo też postanowiło wystawić swojego zawodnika :) Nazywa się on &lt;b&gt;The Yahoo! User Interface&lt;/b&gt; (YUI). Biblioteka ta jest zbiorem narzędzi i kontrolek napisanych w JavaScripcie, do budowania interaktywnych aplikacji webowych. Opiera się w dużej mierze na operowaniu na DOMie, DHTMLu i AJAXie. Wszytkie komponenty dostarczane przez Yahoo są open sourcowe na licencji BSD i można ich używać do woli.&lt;br /&gt;&lt;br /&gt;W celu zaprezentowania podstawowych możliwości Yahoo posłuże się prostym przykładem komponentu &lt;b&gt;AutoComplete&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Aby w ogóle użyc kontrolki musimy załączyć do naszej strony HTML pliki CSS i JavaScript:&lt;pre&gt;&lt;code&gt;&amp;lt;link type="text/css" rel="stylesheet" &lt;br /&gt;  href="http://yui.yahooapis.com/2.3.1/build/autocomplete/assets/skins/sam/autocomplete.css"&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" &lt;br /&gt;  src="http://yui.yahooapis.com/2.3.1/build/yahoo-dom-event/yahoo-dom-event.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" &lt;br /&gt;  src="http://yui.yahooapis.com/2.3.1/build/connection/connection-min.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" &lt;br /&gt;  src="http://yui.yahooapis.com/2.3.1/build/animation/animation-min.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" &lt;br /&gt;  src="http://www.json.org/json.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript" &lt;br /&gt;  src="http://yui.yahooapis.com/2.3.1/build/autocomplete/autocomplete-min.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;Następnie tworzymy instancję pola AutoComplete w następujący sposób:&lt;pre&gt;&lt;code&gt;&amp;lt;div id="myAutoComplete"&amp;gt;&lt;br /&gt;&amp;lt;input id="myInput" type="text"&amp;gt;&lt;br /&gt;&amp;lt;div id="myContainer"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var myAutoComp = new YAHOO.widget.AutoComplete("myInput","myContainer", myDataSource);&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;Konstruktor AutoComplete zawiera trzy parametry:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Identyfikator pola typu texbox lub textarea w które użytkownik będzie wpisywał zapytanie.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Identyfikator elementu HTML który będzie kontenerem zawierającym wyniki zapytania.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wreszcie trzeci parametr to DataSource, który będzie zawierał dane które będą zawężane przez zapytanie i prezentowane w kontenerze.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Zanim zostanie powołany obiekt AutoComplete, należy zainicjować trzeci parametr DataSource można to zrobić na trzy różne sposby w zależności od potrzeb.&lt;br /&gt;&lt;br /&gt;Prosta tablica po stronie przeglądarki:&lt;pre&gt;&lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var myArray1 = ["a", "b", "c"];&lt;br /&gt;var myDataSource1 = new YAHOO.widget.DS_JSArray(myArray1);&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;Funkcja JavaScript, która dostarczy dane:&lt;pre&gt;&lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var myFunction = function() {&lt;br /&gt;var myArray2 = ["d", "e", "f"];&lt;br /&gt;return myArray2.reverse();&lt;br /&gt;}&lt;br /&gt;var myDataSource2 = new YAHOO.widget.DS_JSFunction(myFunction);&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;Wreszcie najbardziej przydatny sposób pociągnięcie danych z serwera:&lt;pre&gt;&lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var myServer = "someServlet";&lt;br /&gt;var mySchema = ["ResultItem", "KeyDataField"];&lt;br /&gt;var myDataSource3 = new YAHOO.widget.DS_XHR(myServer, mySchema);&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;Mam nadzieję, że przykład ten przybliżył zasadę działania YUI. Więcej informacji znajdziecie na stronie:&lt;br /&gt;&lt;a href="http://developer.yahoo.com/yui/"&gt;http://developer.yahoo.com/yui/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Zachęcam również do dyskusji do jakich frameworków webowych należy przyszłość?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-1645030050758663560?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/1645030050758663560/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=1645030050758663560" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/1645030050758663560" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/1645030050758663560" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/10/yui-rywal-gwt_17.html" title="YUI rywal GWT?" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-7551600127325681580</id><published>2007-10-13T20:40:00.004+02:00</published><updated>2008-07-06T16:24:19.847+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="AJAX" /><category scheme="http://www.blogger.com/atom/ns#" term="framework" /><title type="text">Drag&amp;Drop w GWT</title><content type="html">Od czasu kiedy pojawiło się GWT minęło już sporo czasu, dlatego można go już oceniać nie tylko pod kątem tego czy zaproponowana przez Google koncepcja jest właśnie tą na którą czekają programiści webowi, którym dzierganie w JavaScriptcie po prostu nie odpowiada, ale również można oceniać go pod kątem popularności jaką zdobywa i przyznam, że przeglądając zasoby Internetu wyraźnie widać, że pozostawia konkurencję w tyle jak choćby framework YUI tworzony przez Yahoo.&lt;br /&gt;&lt;br /&gt;Innym istotnym elementem, który wpływa w zasadniczy sposób na popularność danego frameworku jest wsparcie jakie zyskuje on w środowisku OpenSource'owym, głównie mam tutaj na myśli ilość darmowych rozszerzeń jaka jest tworzona przez to grono programistów.&lt;br /&gt;Wczoraj przeszukując Internet natrafiłem na bardzo ciekawą bibliotekę &lt;strong&gt;gwt-dnd&lt;/strong&gt;, która przy naprawdę niewielkim nakładzie pracy pozwoli na zbudowanie interfejsu użytkownika z elementami &lt;strong&gt;Drag&amp;amp;Drop&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Podstawową zaletą tej biblioteki jest to, iż możemy korzystać ze standarowych widgetów i paneli dostarczanych przez GWT - nie muszą one implementować specjalnych klas lub interfejsów, po prostu wystarczy użyć istniejące widgety i panele. Nie będę się koncentrował w dalszym opisie nad tym jakie funkcjonalności dostarcza ta biblioteka, natomiast zaprezentuję fragment kodu, który zaprezentuje prostotę użycia tego rozszerzenia.&lt;br /&gt;&lt;br /&gt;W pierwszym kroku tworzymy główny panel poza który nie będą mogły wyjść przeciagane elementy:&lt;pre&gt;&lt;code&gt;AbsolutePanel boundaryPanel = new AbsolutePanel();&lt;br /&gt;boundaryPanel.setPixelSize(400, 300);&lt;br /&gt;RootPanel.get().add(boundaryPanel);&lt;/code&gt;&lt;/pre&gt;Następnie wewnątrz tego panelu tworzymy kolejny panel tym razem będzie on określał obszar poza którym nie będzie można upuścić widgetu (w naszym przypadku będzie to prostu label):&lt;pre&gt;&lt;code&gt;AbsolutePanel targetPanel = new AbsolutePanel();&lt;br /&gt;targetPanel.setPixelSize(300, 200);&lt;br /&gt;boundaryPanel.add(targetPanel, 10, 10);&lt;/code&gt;&lt;/pre&gt;Kolejny krok to stworzenie tzw. DragControllera, w którym umieszczamy panel poza który nie będzie można przeciągać widgetów (co nie znaczy, że będzie można w nim go upuszczać):&lt;pre&gt;&lt;code&gt;DragController dragController = new PickupDragController(boundaryPanel, true);&lt;/code&gt;&lt;/pre&gt;Teraz dodajemy analogicznie tzw. DropController, w którym umieszczamy panel w obrębie którego mogą zostać upuszczone widgety:&lt;pre&gt;&lt;code&gt;DropController dropController = new AbsolutePositionDropController(targetPanel);&lt;/code&gt;&lt;/pre&gt;Rejestrujemy DropController w DragControllerze:&lt;pre&gt;&lt;code&gt;dragController.registerDropController(dropController);&lt;/code&gt;&lt;/pre&gt;Tworzymy etykiete, którą będziemy przeciągać i upuszczać w obrębie targetPanel:&lt;pre&gt;&lt;code&gt;Label label = new Label("Rusz mnie :)", false);&lt;br /&gt;targetPanel.add(label, 10, 1);&lt;/code&gt;&lt;/pre&gt;Za pośrednictwem DragControllera robimy z etykiety widget, który można przeciągać:&lt;pre&gt;&lt;code&gt;dragController.makeDraggable(label);&lt;/code&gt;&lt;/pre&gt;Siła tej biblioteki tkwi w prostocie jej użycia, w 12 liniach kodu można zrobić naprawdę dużo zamieszania :)&lt;br /&gt;&lt;br /&gt;Źródła z których korzystałem i wszystkim polecam się z nimi zapoznać:&lt;br /&gt;&lt;a href="http://code.google.com/p/gwt-dnd/"&gt;http://code.google.com/p/gwt-dnd/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/gwt-dnd/wiki/GettingStarted"&gt;http://code.google.com/p/gwt-dnd/wiki/GettingStarted&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Dla zainteresowanych zamieszczam kody źródłowe.&lt;br /&gt;&lt;br /&gt;Kod źródłowy pliku &lt;code&gt;MyApplication.gwt.xml&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;module&amp;gt;&lt;br /&gt;  &amp;lt;inherits name="com.google.gwt.user.User"/&amp;gt;&lt;br /&gt;  &amp;lt;inherits name="com.allen_sauer.gwt.dragdrop.DragAndDrop"/&amp;gt;&lt;br /&gt;  &amp;lt;entry-point class="com.mycompany.project.client.MyApplication"/&amp;gt;&lt;br /&gt;&amp;lt;/module&amp;gt;&lt;/code&gt;&lt;/pre&gt;Kod źródłowy pliku &lt;code&gt;MyApplication.java&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;package com.mycompany.project.client;&lt;br /&gt;&lt;br /&gt;import com.allen_sauer.gwt.dragdrop.client.DragController;&lt;br /&gt;import com.allen_sauer.gwt.dragdrop.client.PickupDragController;&lt;br /&gt;import com.allen_sauer.gwt.dragdrop.client.drop.AbsolutePositionDropController;&lt;br /&gt;import com.allen_sauer.gwt.dragdrop.client.drop.DropController;&lt;br /&gt;import com.google.gwt.core.client.EntryPoint;&lt;br /&gt;import com.google.gwt.user.client.ui.AbsolutePanel;&lt;br /&gt;import com.google.gwt.user.client.ui.Label;&lt;br /&gt;import com.google.gwt.user.client.ui.RootPanel;&lt;br /&gt;&lt;br /&gt;public class MyApplication implements EntryPoint {&lt;br /&gt; &lt;br /&gt;  public void onModuleLoad() {&lt;br /&gt;    AbsolutePanel boundaryPanel = new AbsolutePanel();&lt;br /&gt;    boundaryPanel.setPixelSize(400, 300);&lt;br /&gt;    RootPanel.get().add(boundaryPanel);&lt;br /&gt;  &lt;br /&gt;    AbsolutePanel targetPanel = new AbsolutePanel();&lt;br /&gt;    targetPanel.setPixelSize(300, 200);&lt;br /&gt;    boundaryPanel.add(targetPanel, 10, 10);&lt;br /&gt;  &lt;br /&gt;    DragController dragController = new PickupDragController(boundaryPanel, true);  &lt;br /&gt;    DropController dropController = new AbsolutePositionDropController(targetPanel);&lt;br /&gt;    dragController.registerDropController(dropController);&lt;br /&gt;  &lt;br /&gt;    Label label = new Label("Rusz mnie :)", false);&lt;br /&gt;    targetPanel.add(label, 10, 1);&lt;br /&gt;  &lt;br /&gt;    dragController.makeDraggable(label);&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-7551600127325681580?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/7551600127325681580/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=7551600127325681580" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7551600127325681580" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/7551600127325681580" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/10/drag-w-gwt.html" title="Drag&amp;Drop w GWT" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3027091649644802032.post-25036656501014810</id><published>2007-10-13T16:53:00.000+02:00</published><updated>2007-10-17T21:10:09.542+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AJAX" /><category scheme="http://www.blogger.com/atom/ns#" term="JSF" /><category scheme="http://www.blogger.com/atom/ns#" term="Portal" /><category scheme="http://www.blogger.com/atom/ns#" term="Portlet" /><title type="text">Portlety w Sun Java Studio Creator 2</title><content type="html">Ostatnio zainteresowałem się nieco poważniej tematyką portali - po zapoznaniu się z kilkoma darmowymi rozwiązaniami zdecydowałem, że w dalszej wędrówce będę korzystał z &lt;a href="http://www.liferay.com"&gt;Liferaya&lt;/a&gt; ze względu na jego stabilność, dojrzałość i duże możliwości oraz zgodność z JSR 168.&lt;br /&gt;&lt;br /&gt;Ze względu na to, iż jestem programistą głównie moją uwagę skupiłem na pisaniu portletów, a że JSP i Servlety są bardzo bliskie mej duszy, pisanie ich nie stanowiło dla mnie najmniejszego problemu - okazało się zajęciem miłym, łatwym i przyjemnym, do czasu...&lt;br /&gt;&lt;br /&gt;Właśnie do czasu kiedy uznałem, że warto by skorzystać z jakiegoś frameworku (nawet więcej - środowiska deweloperskiego), jednak takiego w którym byłoby dużo komponentów na dość wysokim poziomie abstrakcji, graficzne środowisko deweloperskie do projektowania stron WWW np. tak jak w &lt;a href="http://developers.sun.com/prodtech/javatools/jscreator/index.jsp"&gt;Sun Java Studio Creator&amp;nbsp;2&lt;/a&gt;. (Przypomnę, że narzędzie to posiada graficzny edytor do budowania stron JSF.)&lt;br /&gt;&lt;br /&gt;Zanim do tego przystąpiłem zapoznałem sie nieco dokładniej ze &lt;a href="http://jcp.org/en/jsr/detail?id=168"&gt;specyfikacją JSR 168&lt;/a&gt;. Szczególnie zainteresował mnie rozdział &lt;em&gt;CSS Style Definitions&lt;/em&gt;, zawarte są w nim wszystkie standardowe style CSS, które powinny być używane w portletach. Dlaczego powinny być? Otóż dlatego aby każdy portlet wyglądał tak samo pod kątem kolorystyki i stylistyki, którą narzuca wybrany przez użytkownika temat dostępny w konfiguracji portalu. Bo jakże okrutną torturą byłoby dla obiorcy gdyby zobaczył kilka różnych portletów na jednej stronie w zupełnie innej kolorystyce, które nijak nie przystają do całości, a przecież o tą spójność chodzi.&lt;br /&gt;&lt;br /&gt;Postanowiłem sprawdzić jak to jest w praktyce i napisałem trochę kodu w JSF (korzystając ze standardowej implementacji MyFaces zgodnej z &lt;a href="http://java.sun.com/javaee/javaserverfaces/download.html"&gt;JSF 1.2&lt;/a&gt;). Dlaczego akurat wybrałem JSF, ponieważ już zdążyłem się zorientować, iż jest to technologia najbardziej odpowiednia jeżeli chodzi o pisanie portletów - tak wynika z opinii krążących w Internecie.&lt;br /&gt;&lt;br /&gt;Poniżej zamieszczam przykład w JSF napisany zgodnie z rozdziałem &lt;em&gt;CSS Style Definitions&lt;/em&gt;:&lt;pre&gt;&lt;code&gt;&amp;lt;h:form id="edit" styleClass="portlet-font"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;h1 style="portlet-section-header"&amp;gt;&lt;br /&gt;    &amp;lt;h:outputText value="#{text['formtitle']}" /&amp;gt;&lt;br /&gt;  &amp;lt;/h1&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;h:messages globalOnly="true" showDetail="true" &lt;br /&gt;      infoClass="portlet-msg-info" &lt;br /&gt;      warnClass="portlet-msg-alert"&lt;br /&gt;      errorClass="portlet-msg-error"&lt;br /&gt;      fatalClass="portlet-msg-fatal" /&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;h:panelGrid columns="2"&lt;br /&gt;      footerClass="portlet-section-footer" &lt;br /&gt;      headerClass="portlet-section-header" &lt;br /&gt;      styleClass="portlet-section-body"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;h:outputLabel for="name" &lt;br /&gt;        styleClass="portlet-form-field-label"&amp;gt;#{text['name']}&amp;lt;/h:outputLabel&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;h:inputText id="name" &lt;br /&gt;        value="#{formbean.form.creator.name}"                 &lt;br /&gt;        required="true"&lt;br /&gt;        styleClass="portlet-form-input-field"/&amp;gt;   &lt;br /&gt;  &amp;lt;/h:panelGrid&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;h:commandButton id="submit" &lt;br /&gt;      value="#{text['submit']}"&lt;br /&gt;      action="#{formbean.doSave}"&lt;br /&gt;      styleClass="portlet-form-button"/&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;h:commandButton id="cancel"&lt;br /&gt;      value="#{text['cancel']}"&lt;br /&gt;      action="#{formbean.doCancel}"&lt;br /&gt;      immediate="true"&lt;br /&gt;      styleClass="portlet-form-button"/&amp;gt;&lt;br /&gt;&amp;lt;/h:form&amp;gt;&lt;/code&gt;&lt;/pre&gt;Nietrudno zauważyć, że programista w powyższym kodzie skoncentrował się na tym aby używać standardowych stylów CSS ze specyfikacji JSR 168. I właśnie do tej pory było pięknie, niemal sielankowo... Aż nastąpił czas na próbę generalną Sun Java Studio Creator&amp;nbsp;2, środowiska deweloperskiego, które pozwala programiście w kilka minut (no może godzin) niemal wyklikać całą aplikację - co można zobaczyć na prezentacji &lt;a href="http://developers.sun.com/prodtech/javatools/jscreator/overview/tours/prodtour/flash/index.html"&gt;Java Studio Creator 2 in Action&lt;/a&gt;. (Wspomnę tylko, że takie prezentacje na menadżerach robią ogromne wrażenie i nie zawsze jest im łatwo wytłumaczyć, że takie rozwiązanie posiada też pewne wady i koniecznie idealnie pasuje do realiów firmy).&lt;br /&gt;&lt;br /&gt;Stworzyłem stronę JSF, która wykorzystywała kilka dostępnych komponentów: tabelkę, przycisk itd. Ze względu, że Sun generuje dla własnych komponetów swoje style CSS, postanowiłem w jednym z przycisków je przedefiniować na styl zgodny ze specyfikacją JSR 168:&lt;pre&gt;&lt;code&gt;&amp;lt;ui:button id="nextStep"&lt;br /&gt;    action="#{Buy.nextStep_action}" &lt;br /&gt;    binding="#{Buy.nextStep}"&lt;br /&gt;    text="NEXT STEP"&lt;br /&gt;    styleClass="portlet-form-button"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;Jakież było moje zdziwienie, gdy po uruchomieniu portletu powyższa zmiana nie przyniosła skutku. W akcie desperacji zajrzałem do źródła wygenerowanej strony HTML w przeglądarce WWW. Oto efekty:&lt;pre&gt;&lt;code&gt;&amp;lt;input type="button" value="NEXT STEP" &lt;br /&gt;    class="btn2 portlet-form-button" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;Co się okazało komponent wygenerował moją klasę CSS &lt;code&gt;portlet-form-button&lt;/code&gt;, ale wcześniej wstawił swoją &lt;code&gt;btn2&lt;/code&gt; - niestandardową, niezgodną z definicją styli CSS dla portali, a że w klasie &lt;code&gt;btn2&lt;/code&gt; było zdefinowane mnóstwo atrybutów CSS to moja biedna klasa &lt;code&gt;portlet-form-button&lt;/code&gt; niewiel mogła tu przedefinować. Było źle, ale czy może być jeszcze gorzej, okazuje się, że tak. Otóż zaczałem szukać gdzie się podział plik ze stylami CSS, w których znajduję się nieszczęsna definicja &lt;code&gt;btn2&lt;/code&gt;, bo może by dało się go zwariantować osobno dla każdego tematu portalu. Wprowadziłbym oddzielny plik z odrębną definicją styli CSS i umieścił w każdym temacie. Po pewnym czasie znalazł się nieszczęśnik w jednej z bilbiliotek SUNa spakowanej do jara. Jak to działa: w momencie gdy ładowany jest portlet ta biblioteka jest dynamicznie z takiego jara wyciągana i do niego dołączana. Efekt jest taki, że każdy portlet ma swoją definicję styli CSS, co nie do końca przystaje do standardu JSR 168.&lt;br /&gt;&lt;br /&gt;Występują też inne problemy związane z tym co napisałem powyżej. Jeżeli będziemy chcieli uruchomić dwa portlety napisane właśnie w środowisku deweloperskim SUN od dwóch niezależnych dostawców, z których każdy zastosował inne style CSS np. blue.css i gray.css. To wówczas obydwa portlety przyjmią style od portletu, który uruchomi się ostatni - czyli mamy do czynienia z swego rodzaju loterią, bo to użytkownik może decydować o kolejnośći ich występowania (rozmieszczanie portletów na stronie).&lt;br /&gt;Problem ten można rozwiązać poprzez zastosowanie pewnego obejścia zaproponowanego na blogu pracownika Suna &lt;a href="http://blogs.sun.com/gregz/entry/conflicting_creator_themes_in_portlets"&gt;Conflicting Creator Themes in Portlets&lt;/a&gt;. Proponuje on dołączenie kolejny raz stylu CSS w stopce, czyli przy dwóch portletach będziemy mieć trzy definicje stylów oraz definicje standardowe dla danego portalu.&lt;br /&gt;&lt;br /&gt;Wszystko podsumuję starym przysłowiem: &lt;em&gt;Nie wszystko złoto co się świeci&lt;/em&gt; - mimo, że środowisko deweloperskie Sun Java Studio Creator&amp;nbsp;2 na pierwszy rzut oka oferuję naprawdę dużo, to poważne błędy konstrukcyjne dyskwalifikują je z użycia przy budowaniu portletów.&lt;br /&gt;&lt;br /&gt;W czym taki razie pisać portlety skoro standardowa implementacja JSF 1.2 okaże się niewystarczająca, bo oczekiwania są większe (np. tabelki ze stronicowaniem, sortowaniem itd.) może użycie komponentów &lt;a href="http://myfaces.apache.org/tomahawk/index.html"&gt;Tomahawk&lt;/a&gt; w połączeniu z &lt;a href="https://ajax4jsf.dev.java.net/nonav/ajax/ajax-jsf/"&gt;ajax4jsf&lt;/a&gt;? Niektóry firmy właśnie na takie połączenie stawiają &lt;a href="http://www.jsfcentral.com/articles/katz-06-16-06.html"&gt;Interview with Max Katz&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Zachęcam do dyskusji &lt;em&gt;W czym pisać portlety (JSR-168) w sposób efektywny, ale i zgodny ze sztuką?&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3027091649644802032-25036656501014810?l=coderlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://coderlife.blogspot.com/feeds/25036656501014810/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3027091649644802032&amp;postID=25036656501014810" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/25036656501014810" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3027091649644802032/posts/default/25036656501014810" /><link rel="alternate" type="text/html" href="http://coderlife.blogspot.com/2007/10/portlety-w-sun-java-studio-creator-2.html" title="Portlety w Sun Java Studio Creator 2" /><author><name>Łukasz Pawlik</name><uri>http://www.blogger.com/profile/04167291407338846196</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry></feed>

