Archive

Archive for the ‘Java’ Category

JPA Translator – przykładowy war + JSF

December 10th, 2007 No comments
Witam! Dla wszystkich, którzy chcą szybko zobaczyć na jak działa jpa-translator w dziale download zamieściłem przykładową aplikację webową. Można ją uruchomić na nowoczesnym kontenerze WEB, na przykład: Tomcat, Jetty. Pozdrawiam
Categories: Java, JPA Tags:

JPA Translator się rozwija

December 5th, 2007 No comments
Witam,
Mój projekt translatora dla JPA rozwija się dobrze. Ze źródeł SVN można pobrać działającą aplikację wykorzystującą mój translator, OpenJPA i JSF.
Pozdrawiam i zapraszam do rozwijania projektu.
Categories: Java, JPA Tags:

NetBeans 6

December 4th, 2007 2 comments
Wersja 6 NetBeans jest już dostępna!!! To znakomite IDE, które wybieram ze względu na: Od pewnego czasu przyglądałem się kolejnym wydaniom beta i release candidate. Były coraz lepsze, działały coraz szybciej, muliły się coraz rzadziej. Wszystko szło w dobrym kierunku. Właśnie instaluje wersje NetBeans 6.0!!!
Categories: Java Tags:

Tłumaczenia w aplikacji na wiele sposobów

December 3rd, 2007 6 comments
Zdarzyło mi się napisać aplikacje WWW, która miała działać w wielu krajach, w wielu językach. Potrzebowałem systemu tłumaczeń. Mówiąc systemu mam na myśli systematyczne podejścia do sprawy tłumaczeń. Tłumaczenia w mojej aplikacji są częścią jej biznesu. Najprościej zrozumieć to na przykładzie. Jest sobie hotel który ma opis. Ten opis może być przetłumaczony na wiele języków. Do systemu można wprowadzić nowe hotele a każdy z nich będzie miał inne tłumaczenie. Wyobraźmy sobie tabelkę hotel. Ma ona trzy pola: identyfikator, nazwa i opis. Opis to coś co trzeba przetłumaczyć. Ale jak to zrobić?
create table hotel(
  primary key int id,
  varchar nazwa,
  varchar opis
)
Istnieje wiele sposobów rozwiązania tego problemu. Do głowy przychodzą mi takie:
  • W systemie tworzymy tabelę hotel zawierającą kolumnę opis dla każdego z dostępnych języków. Będzie to wyglądać mniej więcej tak:
    table hotel(
      primary key int id,
      varchar nazwa,
      varchar opis_en, 
      varchar opis_de, 
      varchar opis_pl
    )
    
    Przedstawione rozwiązanie powinno działać bardzo szybko, jednak ma wadę – dodanie kolejnego języka do wymaga modyfikacji bazy danych – a to jest brzydkie.
  • Dla każdej wersji językowej tworzymy osobną tabelę zawierającą pola, które trzeba przetłumaczyć. Wygląda to mniej więcej tak:
    table hotel(
      primary key int id,
      varchar nazwa,
    )
    table hotel_en(
      primary key int id,
      varchar opis
    )
    table hotel_pl(
      primary key int id,
      varchar opis
    )
    
    To rozwiązanie będzie działać szybko. Dodanie nowego języka będzie wymagać modyfikacji bazy danych. Oczywiście, korzystając z tego lub z poprzedniego rozwiązania warto napisać program, który będzie tłumaczył zapytania SQL i pobierał dane z odpowiednich tabel językowych. Obydwa te rozwiązania będą działać szybko jednak moim zdaniem nie są one ładne.
  • Znam jeszcze coś takiego:
    table hotel(
      primary key int id,
      varchar nazwa
    )
    table hotel_tłumaczenia(
      primary key int id,
      int identyfikator_języka,
      varchar opis
    )
    
    To rozwiązanie jest lepsze od poprzednich tym, że wprowadzenie do systemu nowego języka nie będzie wymagało zmiany w strukturze danych.
  • Ja najbardziej lubiłem jednak tworzenie tablicy słownikowej. W uproszczeniu wygląda to tak:
    table słownik (
      primary key int identyfikator_tłumaczonego_tekstu,
      int identyfikator_języka,
      varchar tłumaczenie
    )
    table hotel(
      primary key int id,
      varchar nazwa,
      identyfikator_tłumaczonego_tekstu opis
    )
    
    To rozwiązanie jest o tyle fajne, że proste. Nie wymaga modyfikacji struktury bazy danych w momencie dodania nowego języka. Łatwo też pisać zapytania SQL, które pobierają teksty w wybranym języku. Niestety, to rozwiązanie jest wolniejsze, szczególnie wtedy gdy tabelka hotel ma wiele pól które chcemy przetłumaczyć.
Myślę, że można wymyślić jeszcze wiele innych rozwiązań tego problemu. Schemat myślenia można przenieś ze świata relacji do języków programowania obiektowego. Można zrobić też coś takiego:
@Entity
class Hotel{
  @Id
  private Long id;
 
  private String nazwa;

  @Tłumaczenie
  private String opis;
}
Tak to nowa JAVA. Dzięki adnotacjom możemy programować wielowymiarowo. Więc dlaczego by nie stworzyć dla naszej aplikacji nowego wymiaru – wymiaru tłumaczeń??? Ja właśnie to robię. Tworzę bibliotekę Java, która programistom będzie dostarczać wygodnego narzędzia rozwiązującego problem tłumaczeń. Tłumaczenia, nie będą już częścią aplikacji. Będą jej nowym wymiarem. Zainteresowanych zapraszam do projektu: JPA Translator
Categories: Java, JPA, SQL Tags:

JBoss SEAM i EJB-QL injection

October 11th, 2007 2 comments
A jednak. Nawet tak zaawansowany framework jak JBoss SEAM może być podatny na ataki EJB-QL injection. EJB-QL injection jest podobny do SQL injection, z tą różnicą że nie atakujemy kodu SQL a kod EJB-QL. Mam najnowszą wersję: jboss-seam-2.0.0.CR2. Błąd jest w pomyślne na klasę: org.jboss.seam.framework.Query w metodzie getRenderedEjbql(). Czytamy tam:
if ( getOrder()!=null ) builder.append(" order by ").append( getOrder() );
return builder.toString();
Parametr order pochodzi z żądania HTTP. To co zły człowiek możemy zrobić zależy od implementacji JPA i serwera bazy danych. Mi nie przychodzi akurat nic złego do głowy. Uważam jednak, że ten kod biblioteki SEAM trzeba jeszcze raz przemyśleć i koniecznie przepisać. Zapewne pogadamy o tym na Warszawskim JUGu. Aktualizacja po przerwie na kanapkę. W nagrodę za znalezienie błędu w SEAMie postanowiłem zjeść kanapkę. Dawka energii sprawiła, że znalazłem szybkie rozwiązanie. W klasie dziedziczącej – implementującej naszą listę obiektów musimy ustalić listę dozwolonych sortowań, na przykład tak:
private static final String[] ORDERS = {name asc","name desc","id asc","id desc"};
@Override
public void setOrder(String order){
  if (Arrays.asList(ORDERS).contains(order)) {
    super.setOrder(order);
  }
}
W ten sposób zabezpieczymy się przed ryzykiem na przykład tego, że zły człowiek wciśnie nam sortowanie po procedurze SQL odpowiedzialnej za kasowanie userów.
Categories: Java, JPA Tags:

Gorący kod: Eclipse i JBoss

August 1st, 2007 No comments
Witam! Odkryłem dziś cudowną funkcjonalność Eclipse – dynamiczną wymianę kodu klas uruchomionych na serwerze JBoss. Korzystając z Eclipse 3.3 uruchomienie dynamicznej wymiany kody klas (hot code replacement) jest bardzo proste. Wystarczy uruchomić serwer JBoss w trybie DEBUG. Przy pierwszym uruchomieniu trzeba też postawić breakpoint w kodzie klasy, którą chcemy wymienić. To tyle ;) To dla mnie wielki prezent. Oszczędzam wiele godzin, które marnowałem restartując mój projekt. Pozdrawiam
Categories: Eclipse, Java Tags:

Miesiąc miodowy z JPA

July 30th, 2007 No comments
Witam, Od miesiąca jestem szczęściarzem, gdyż mogę pracować z technologią JPA. Chciałbym podzielić się wrażeniami.
  • W projekcie powstaje bardzo przyjemny kod. Adnotacje, opisującej jak nasze obiekty mają być mapowane do tabel w bazie danych to na prawdę fajna sprawa.
  • Nie miałem jeszcze żadnych problemów z działaniem, poza tymi, które wynikały z mojej niewiedzy, lub niewłaściwego stosowania technologii. Wszystkie problemy dało się rozwiązać bardzo szybko i bezkompromisowo – tj. bez brzydali w kodzie kodzie
  • Ręczne zarządzanie EntityManagerem jest możliwe. Ułatwia testowanie. Brakuje mi jednak zarządzania transakcjami przez serwer aplikacji (nie stosuje EJB3).
  • EJB-QL jest fajny. Fajne są zapytania o składni “from PozycjeFaktury where faktura.klient=:klient” – zastępują one serię joinów. Ale jeszcze fajniejsze jest zapytanie z użyciem operatora “IN”, (odsyłam do strony Jacka Laskowskiego – “IN” to temat na osobnego posta).
  • Java jest fajna. Przesiadka na Javę była jedną z najlepszych decyzji w moim życiu.
Za tydzień rozpoczynam kolejny miesiąc miodowy. Tym razem już taki całkiem prawdziwy. W sobotę w samo południe poślubiam Aleksandrę Kocewiak. To wspaniała kobieta i jestem najszczęśliwszym facetem na ziemi. Wszystkich, którzy chcą zobaczyć nasz ślub zapraszam do kościoła: Parafia NMP Matki Kościoła, ul. Domaniewska 20, Warszawa – w sobotę 4 sierpień 2007 godzina 12:00.
Categories: Java, JPA Tags:

Prawdy o equals

June 23rd, 2007 10 comments
Witam, W języku Java, jest fajna metoda – equals(). Służy ona do porównywania, czy dwa obiekty są sobie równe. Czyli, na przykład obiekt Osoba implementuje metodę equals, i sprawdza czy imię i nazwisko tej osoby są takie same. Implementując metodę equals, należy pamiętać, że może z niej korzystać nie tylko Twój kod, ale także kod innych bibliotek do których przekazujesz obiekty, np.: Hibernate, JiBX, Axis. Implementując metodę equals w tworzonym właśnie obiekcie, należy pamiętać, że Java spodziewa się określonego działania tej metody. Dla metody equals określono 5 bardzo logicznych warunków. A więc:
  • metoda equals musi być zwrotna, czyli a.equals(a)==true.
  • metoda equals musi być symetryczna, czyli a.equals(b)==b.equals(a).
  • metoda equals musi być przechodnia, czyli jeżeli a.eqauls(b)==true i b.equals(c)==true to a.equals(c)==true. (Jednak gdy: a.equals(b)==false i b.equals(c)==false to a.equals(c) może być true)
  • metoda equals musi być konsekwenta, czyli gdy dwa razy (w różnych chwilach czasu) porównujemy te same obiekty, to wynik tego porównania powinien być taki sam.
  • obiekt jest nie równy null, czyli a.equals(null)==false dla każdego a nie będącego null
Wszystkie te warunki są tak samo ważne, jednak 3 pierwsze dają największe pole do popełnienia błędów. Błędne działanie metody equals, może być trudne do wykrycia i często będzie wyglądać jak błąd w innej bibliotece. Wyobraźmy sobie, że na przykład JiBX (taka biblioteka do serializacji do XMLa) podczas serializacji złożonej struktury danych zapisuje sobie gdzieś, jakie obiekty były już serializowany, tak by nie serializować dwa razy tego samego obiektu. Tymczasem metoda equals oszukuje, i JiBX próbuje 1000 razy marshalować ten sam obiekt. Programista zobaczy komunikat o braku pamięci, pomyśli – j… OpenSource – nic nie działa – tymczasem błąd może tkwić w jego kodzie w tak oczywistej metodzie equals. To oczywiście tylko hipoteza, ale tak może być. Proponuję pisać metodę equals na przykład tak.
public class Osoba {
  private String imie;
  private String nazwisko;

  public boolean equals(Object innyObiekt) {
    if (this == innyObiekt) return true;
    if (!( this.getClass().equals(innyObiekt.getClass()) )) return false;
    Osoba innaOsoba = (Osoba) innyObiekt;
    return (null == getImie() ? null == innaOsoba.getImie() : getImie()
        .equals(innaOsoba.getImie()))
        && (null == getNazwisko() ? null == innaOsoba.getNazwisko()
            : getNazwisko().equals(innaOsoba.getNazwisko()));
  }
Warto zapamiętać bardzo ładną konstrukcję: a==null ? b==null : a.equals(b) . Zaoszczędzi nam ona sporo pisania. Dla skomplikowanej metody equals należy pisać test, np. coś takiego:
public class OsobaTest {
  @Test
  public void testEqualsObject() {
    Osoba antek1 = new Osoba();
    antek1.setImie("Antek");
    assertTrue("Zwrotna",antek1.equals(antek1));
    
    Osoba ola = new Osoba();
    ola.setImie("Ola");
    assertFalse("Antek to nie Ola",antek1.equals(ola));
    
    Osoba antek2 = new Osoba();
    antek2.setImie("Antek");
    
    assertTrue("Antek to Antek2",antek1.equals(antek2));
    assertTrue("Symetryczna",antek1.equals(antek2)&&antek2.equals(antek1));
    
    Osoba antek3 = new Osoba();
    antek3.setImie("Antek");
    
    assertTrue("Antek to Antek",antek2.equals(antek3));
    assertTrue("Przechodnia",
        antek1.equals(antek2)==true&&antek2.equals(antek3)&&antek1.equals(antek3));
    
    assertFalse("Antek to nie null",antek1.equals(null));
    
  }
}
Jak widać, z prostą metodą equals może być dużo zabawy. Jednak to bardzo ważne, żeby jej nie zepsuć. Inaczej nasz obiekt, nie będzie działał prawidłowo w świecie Java. Na zakończenie dodam, że warto też poczytać o metodzie hashCode(). Pozdrawiam
Categories: Java Tags:

Collection vs List

June 15th, 2007 No comments
Postanowiłem, że napiszę kilka słów z podstaw języka Java. Dla początkującego w tym języku programisty (takiego jak ja) łatwo jest pomylić interfejsy: java.util.Collection i java.util.List. Otóż List jest wyspecjalizowaną kolekcją przechowującą obiekty w określonej kolejności. Collection nie gwarantuje kolejności elementów.
Categories: Java Tags:

Hibernate i logowanie zapytań SQL wraz w wartościami parametrów

June 1st, 2007 No comments
Witam. Hibernate potrafi logować zapytania SQL. Można to skonfigurować na kilka sposobów. Ja wybrałem konfiguracje z log4j:
# logowanie zapytań SQL
log4j.logger.org.hibernate.SQL=DEBUG, R
log4j.additivity.org.hibernate.SQL=false
# logowanie wartości wstawianych do SQL
log4j.logger.org.hibernate.type=DEBUG
Pozdrawiam!
Categories: JPA, ORM Tags: