May 6, 2007

ADF - Υπολογισμός αθροισμάτων (sums)

To ADF παρέχει ένα ισχυρό και άκρως παραγωγικό πλαίσιο ανάπτυξης λογισμικού, που διασυνδέει de-facto standards της αγοράς (όπως EJB3 και JSF) για τη δόμηση γρήγορων και επεκτάσιμων λύσεων. Με λογική drag-and-drop στοιχεία και δεδομένα παίρνουν θέση στις σελίδες μας, διευκολύνοντας το προγραμματιστικό έργο. Η εμφάνιση ενός πίνακα δεδομένων σε μια σελίδα JSF είναι απλή υπόθεση, απλά σέρνουμε το data control μας (π.χ. view object των ADF BC ή ένα collection από entity EJBs) και ο πίνακας σχηματίζεται. Αυτό που έχει την αξία του, και δεν προσφέρεται αυτόματα από το πλαίσιο, είναι η εμφάνιση μια γραμμής αθροισμάτων (sums) για τις αριθμητικές στήλες του πίνακα. Στο άρθρο αυτό θα περιγραφεί μια λύση εμφάνισης αθροισμάτων, για οποιοδήποτε πίνακα ADF. Η λύση αυτή περιλαμβάνει τα ακόλουθα βήματα:
  1. Δημιουργία επιχειρηματικής λογικής που θα υπολογίζει τα αθροίσματα
  2. Ενεργοποίηση της επιχειρηματικής λογικής από το ADF
  3. Μορφοποίηση των σελίδων ώστε να εμφανιστούν τα αθροίσματα (sums)


Ως προς το πρώτο βήμα, είναι σημαντικός ο προσδιορισμός των στοιχείων που εμφανίζονται εκείνη τη στιγμή στην σελίδα μας. Αυτή η πληροφορία μας παρέχεται από τον Data Control Iterator του ADF που διατρέχει μια λίστα τιμών (collection) για να την παρουσιάσει. Κάνοντας drag-and-drop ένα Data Control σε μια σελίδα, δημιουργείται αυτόματα (αν δεν έχει συμβεί) ήδη μια καταχώρηση του Iterator στο συνοδεύον page definition αρχείο κάθε ADF-bound σελίδας. Για παράδειγμα της μορφής:

Binds="OrderItemsView1" DataControl="AppModuleDataControl"/>

Προγραμματιστικά, για να αποκτήσουμε πρόσβαση στον Iterator χρειάζεται ο ακόλουθος κώδικας:
FacesContext fc = FacesContext.getCurrentInstance(); ValueBinding expr = fc.getApplication().createValueBinding("#{bindings.OrderItemsView1Iterator"}"); DCIteratorBinding ib = (DCIteratorBinding)expr.getValue(fc);

Σχεδιαστικά λοιπόν, δημιούργησα μια νέα κλάση (έστω ADFSumCalculator.java) και μια μέθοδο της μορφής:

public Map calculateSums(String iteratorName)

που παίρνει σαν παράμετρο το όνομα του iterator και επιστρέφει ένα Map από ονόματα στηλών και τα αθροίσματα τους (java.lang.String-->java.lang.Double). Σε αυτή τη μέθοδο λοιπόν αφότου αποκτήσουμε πρόσβαση στον iterator όπως περιγράφηκε παραπάνω, μπορούμε να διατρέξουμε τις στήλες του, με την ανάθεση:

AttributeDef[] attribs = ib.getAttributeDefs();

που μας επιστρέφει τους ορισμούς κάθε στήλης. Το να εξετάσουμε αν περιλαμβάνει αριθμητικά πεδία είναι εύκολη υπόθεση, με μια δήλωση του στυλ:

boolean isNumericAttrib = "oracle.jbo.domain.Number".equals(attribs[i].getJavaType().getName());

καθότι τα πεδία που κατασκευάζονται από ADF BC αντιστοιχίζονται σε αυτόν τον τύπο δεδομένων. Αφότου λοιπόν έχουμε βρει τις αριθμητικές στήλες, ο υπολογισμός των αθροισμάτων που περιλαμβάνουν γίνεται ως εξής:

// Iterate over DCIterator data. Row[] rows = ib.getAllRowsInRange();

έτσι παίρνουμε δηλαδή τις γραμμές που εμφανίζει εκείνη τη στιγμή ο iterator. Μια απλή διάτρεξη αυτών των γραμμών και η χρησιμοποίηση της μεθόδου getAttribute(attributeName) για τις αριθμητικές στήλες που ανακτήσαμε στην προηγούμενη φάση, μας δίδει τα αποτελέσματα. Ο πηγαίος κώδικας παρατίθεται στην επόμενη εικόνα.

Μετά από αυτό, δημιουργούμε ένα Data Control για την κλάση που μόλις δημιουργήσαμε κάνοντας δεξί click σε αυτήν στον Application Navigator, και διαλέγοντας Create Data Control. Αυτό το data control είναι αρκετά generic και μπορεί να χρησιμοποιηθεί από πολλαπλές σελίδες.

Μεταφερόμαστε τώρα στη σελίδα μας, και κάνουμε drag-and-drop της μεθόδου calculateSums() ως ADF Command Button, κάτω από τον πίνακα των στοιχείων μας.

Για την αυτόματη εκτέλεση της διαδικασίας των αθροισμάτων κατά τη φόρτωση της σελίδας, πηγαίνουμε στο Page Definition της σελίδας μας, και δημιουργούμε στην ενότητα executables, δυο νέες μεταβλητές, μια για το όνομα του iterator, και μια δεύτερη για το όνομα της μεταβλητής που θα αποθηκεύσει το αποτέλεσμα της κλήσης στη μέθοδο του κατασκευάσαμε (έστω το όνομα της μεταβλητής sumTab)

Τώρα ήρθε η ώρα να αναθέσουμε την μεταβλητή του ονόματος του iterator σαν παράμετρο της μεθόδου μας.

Και τέλος, για να ορίσουμε πότε θα γίνεται η κλήση της μεθόδου και κατά συνέπεια η ενημέρωση των αθροισμάτων, αρκεί στην ενότητα executables να δημιουργήσουμε ένα νέο invokeAction, που θα κάνει bind στη μέθοδο και θα καλείται όταν γίνεται render το μοντέλο.

Στο τρίτο βήμα, οι αναγκαίες αλλαγές στη σελίδα μας για την εμφάνιση των αποτελεσμάτων είναι βασικά δυο. Πρώτον, συμπερίληψη του facet footer σε κάθε κολόνα που θα θέλαμε το άθροισμα της, καθώς και ενός empty facet footer για τον πίνακα. Το αρχικό κουμπί που κάναμε drag-and-drop μπορεί πια να μην εμφανίζεται (ορισμός attribute rendered=false)

Το αποτέλεσμα θα έχει κάπως ως εξής:

No comments: