Nov 3, 2011

Πώς να κάνουμε αναζήτηση σε πεδίο πολλαπλών επιλογών στο JHeadstart 11g

Το παράδειγμα που πρόκειται να περιγράψω αφορά τη ρύθμιση ενός πεδίου ώστε να γίνεται σε αυτό προχωρημένη αναζήτηση (advanced search) ενώ ο χρήστης έχει ορίσει σε αυτό πολλαπλές τιμές (multiple values) ως κριτήρια. Τα βήματα αφορούν την τελευταία παραγωγική έκδοση του JHeadstart (11.1.1.3) ενώ πληροφορίες για κάτι ανάλογο στην έκδοση 10g θα βρείτε εδώ. Τα πράγματα μάλιστα περιπλέκονται λίγο παραπάνω καθώς το πεδίο προς αναζήτηση δεν θα αποτελεί attribute του view object αλλά θα χρησιμοποιείται απλά ως bind variable.

Η προσέγγιση που θα ακολουθήσουμε αφορά την κατασκευή ενός κατάλληλου where clause στο View Object μας, ώστε το bind variable μας να περιλαμβάνει πολλαπλές τιμές. Γι' αυτό το λόγο, θα χρησιμοποιήσουμε την συνάρτηση regexpr_like της Oracle (αντί ενδεχόμενα του τελεστή IN) ώστε να κάνουμε σύγκριση με τις πολλαπλές καταχωρήσεις του χρήστη. Φτιάχνουμε λοιπόν μια έκφραση του στυλ:

WHERE regexpr_like(table_column, :bind_variable)

όπου ο τύπος της bind variable είναι java.lang.String

Για να υποστηριχθεί αυτή η έκφραση από τον εσωτερικό μηχανισμό αναζήτησης του JHeadstart, χρειάζεται να κάνουμε override το JhsApplicationModuleImpl και ειδικά να ξαναγράψουμε (copy-paste) τη συνάρτηση advancedSearch() ώστε στο κομμάτι που γίνεται ο υπολογισμός των bind variables, να περάσουμε τη λογική του regular expression.Πιο συγκεριμένα, ακολουθούν τονισμένες οι γραμμές της αλλαγής, που διαχειρίζονται τις πολλαπλές τιμές:

if (isBindParam) {
// work around for bug 4714529
if (!value.startsWith("[")) { // Array container as parameter.
vo.ensureVariableManager().setVariableValue(attribute, value);
vo.ensureVariableManager().setVariableValue(attribute, value);
vo.setNamedWhereClauseParam(attribute, value);
sLog.info("Search item matches query bind param " +
attribute + ", value set to " + value);
} else { // Array container.
sLog.info("=Array container for search found...." + value);
String attrValue = "^".concat(value.substring(1, value.length() - 1).replaceAll(",", "\\$\\|\\^").replaceAll(" ", "") + "$");
vo.ensureVariableManager().setVariableValue(attribute, attrValue);
vo.ensureVariableManager().setVariableValue(attribute, attrValue);
vo.setNamedWhereClauseParam(attribute, attrValue);
}
Πρακτικά αυτό που συμβαίνει είναι πως το array container της μορφής: "[10, 46]" που περιγράφει τα κλειδιά των στοιχείων που έχει επιλέξει ο χρήστης μετασχηματίζεται σε regular expression ως εξής: "^10$|^46$" ώστε να περάσει ως τιμή στην bind variable μας. Δεν ξεχνάμε να ορίσουμε πως το Application Module μας κληρονομεί από την κλάση που μόλις φτιάξαμε.

Τώρα, στο επίπεδο του JHeadstart, ορίζουμε ένα unbounded πεδίο με Java type String, τύπο εμφάνισης list και φυσικά το αντίστοιχο Domain όπως περιγράφεται και στο JHS Developer's Guide (7.1.7 Using Query Bind Variables in JHeadstart Quick or Advanced Search)

To template του display type "list" του JHeadstart είναι βασισμένο στο af:selectOneListbox component, οπότε το αλλάζουμε σε selectManyListbox για το πεδίο του ενδιαφέροντός μας.

Έχουμε σχεδόν τελειώσει μιας και μπορούμε να κάνουμε αναζήτηση με πολλαπλές επιλογές. Αυτές μεταφέρονται ως java.lang.String array format στο ADF BC και εμείς εφαρμόζουμε τον regular expression μετασχηματισμό μας.

Κάτι τελευταίο έχει να κάνει με τη συμπεριφορά του Reset query button. Για να πάνε όλα σωστά, θα πρέπει να φτιάξουμε το δικό μας JHS Search bean (κληρονομώντας από το JhsSearchBean) με μια μόνη μέθοδο που θα καθαρίζει τα κριτήρια μας και ειδικά τη bind variable μας, πχ:

@Override
public void clearSearchCriteria(ActionEvent event) {
getIterBinding().getViewObject().setNamedWhereClauseParam("SalsSndId", null);
super.clearSearchCriteria(event);
}