niedziela, 10 października 2010

ADF Business Components i zatwierdzanie transakcji - problem z obsługą wyjątków

W tym tygodniu spędziłem parę godzin na znalezieniu problemu, czemu nagle po wgraniu patch'a na serwer aplikacyjny Oracle'a przestała działać jedna z funkcji. Wyglądała mniej wiecej tak:
public void addDepartment(Number deptno, String dname, String loc){
        
        ViewObject depts = getDeptView();
        Row newDept = depts.createRow();
        newDept.setAttribute("Deptno", deptno);
        newDept.setAttribute("Dname" , dname);
        newDept.setAttribute("Loc"   , loc);
        
        getDBTransaction().commit();
    }
czyli nie robiła nic nadzwyczajnego poza zapisem wiersza do tabeli w bazie. Problem oczywiście odnalazł się w logach serwera. Po zrobieniu upgrade'u z wersji 10.1.3.3 do wersji 10.1.3.5 okazało się, że identyfikator sesji nie ma już 44 znaków tylko 64, a moja funkcja zapisywała ten identyfikator do bazy. Niestety framework nie propagował tego wyjątku do warstwy widoku-controlera i nie dodawał go do kolejki FacesMeassages. Oczywiście prawidłowo napisana funkcja w module aplikacji powinna wyglądać następująco:
public void addDepartment(Number deptno, String dname, String loc){
        
        ViewObject depts = getDeptView();
        Row newDept = depts.createRow();
        newDept.setAttribute("Deptno", deptno);
        newDept.setAttribute("Dname" , dname);
        newDept.setAttribute("Loc"   , loc);
        
        try{
            
            getDBTransaction().commit();
            
        }catch(JboException ex){
            
              getDBTransaction().rollback();
              throw new JboException(ex);
        }
    }
Jak widać, wbrew marketingowi, Oracle ADF nie robi za nas wszystkiego :). Warto o tym pamiętać, szczególnie wywołując procedury PL/SQL.

wtorek, 28 września 2010

Integracja aplikacji JSF z Eclipse Birt z wykorzystaniem Scripting API

Niniejszy wpis dotyczyć będzie integracji aplikacji JSF (w moim przypadku to RichFaces) z technologią raportowania Eclipse Birt. Moja aplikacja ma podpiętą przeglądarkę Birt Viewer, która służy mi do pobrania raportów w formacie PDF czy Excel. To co mnie interesowało to przekazanie do raportu listy pracowników oraz nagłówka.

Poniżej kod mojego managed beana:

Kluczowy dla komunikacji pomiędzy moją aplikacją a silnikiem Birt'a jest poniższy fragment kodu:





Czas na handlery - czyli klasy odpowiadające za podstawienie przesłanych danych do szablonu raportu. Pierwszy odpowiada z przechwycenie parametrów:

















Drugi odpowiada za przechwycenie listy wierszy tabeli:



































W obu przypadkach widać, że do danych przesłanych do raportu uzyskujemy dostęp dzięki klasie IReportContext.
Teraz wystarczy już tylko utworzyć w raporcie źródło danych - w moim przypadku będzie to Scripted Data Source oraz korzystający z tego źródła Data Set.

Należy też dodać parametr - będący nagłówkiem raportu





















Na koniec trzeba jeszcze podłączyć do raportu utworzone wcześniej handlery:








środa, 22 września 2010

Web Services – usługa i klient z wykorzystaniem Apache Axis 2 i Eclipse Galileo

Mój zbliżający się wielkimi krokami projekt oparty będzie o usługi sieciowe w związku z czym, postanowiłem rozpoznać temat i zobaczyć jakie jest wsparcie w Eclipse i co sprawdzi się lepiej – Apache Axis 2 czy JAX-WS (Java API for XML Web Services). Zacznijmy od Axisa – nie wymaga in kontenera EJB w związku z czym użyłem Tomcata 6.
W Eclipse wybieramy File → New → Dynamic Web Project
Do utworzenia mojego Web Service'u wybrałem podejście bottom-up czyli utworzenie usługi z klasy Java. Alternatywnie można wybrać podejście top-down czyli utworzenie usługi na bazie istniejącego dokumentu WSDL.
Poniżej moja klasa z jedną metodą
public class AxisDemoService {
 
 public String sayHello(String name){
  return "Hello "+name;
 } 
}

Następnie wybieramy File –> New → Web Service
W następnym kroku należy wybrać funkcje dostępne dla naszej usługi
 
i wystartować server
To czy usługa została poprawnie uruchomiona można sprawdzić pod adresem: http://localhost:8080/AxisWS/services
Czas na utworzenie aplikacji klienckiej. Ja zrobię to w osobnym projekcie o nazwie AxisWSClient.
Ponownie wybieramy File → New → Dynamic Web Project , a następnie File –> New → Web Service Client. Wskazujemy na lokalizację naszego dokumentu WSDL:
Poniżej wygenerowany z automatu kod mojej aplikacji klienckiej.
 
Czas na mały test. Utworzyłem w tym celu dodatkową klasę
import java.rmi.RemoteException;

public class AxisDemoServiceTest {

    public static void main(String[] args) throws RemoteException {
        
        AxisDemoServiceProxy proxy = new AxisDemoServiceProxy();
        proxy.setEndpoint("http://localhost:8080/AxisWS/services/AxisDemoService?wsdl");
        
        String message = proxy.sayHello("Kuba");
        System.out.println(message);

    }
} 

Warto jeszcze zabezpieczyć usługę. W tym celu wykorzystałem najprostszą z możliwych autentykację typu BASIC. W pliku konfiguracyjnym tomcat-users.xml dodałem użytkownika

  
  


i stworzyłem odpowiednie wpisy w pliku web.xml

   
    Axis Services
    /services/*
   
   
    ws_role
   
  
  
   BASIC
   Axis WS Realm
  

Moja klasa testowa w aplikacji klienckiej także wymagała małej modyfikacji
public class AxisDemoServiceTest {

 public static void main(String[] args) throws RemoteException {
  
  AxisDemoServiceProxy proxy = new AxisDemoServiceProxy();
  proxy.setEndpoint("http://localhost:8080/AxisWS/services/AxisDemoService?wsdl");
  
  AxisDemoServiceSoapBindingStub stub = (AxisDemoServiceSoapBindingStub)proxy.getAxisDemoService();
        stub.setUsername("ws_user");
        stub.setPassword("ws_password");
  
  String message = proxy.sayHello("Kuba");
  System.out.println(message);

 }
}

Działa.