ADFHow to Bring Common UI Patterns to ADFLuc Bors, AMIS, The NetherlandsWednesday, June 27, 2012ODTUG KScope 12San Antonio...
UI PATTERNS
FUSION APPS PATTERNS
RECOGNIZE THESE ?
RECOGNIZE THESE ?
TABBED NAVIGATION
TABBED NAVIGATION
CLOSE ALL / CLOSE OTHERS
CLOSE ALL / CLOSE OTHERS
CLOSE ALL / CLOSE OTHERS• e
CAN YOU DO THIS IN ADF ?
CREATE THE CONTEXT MENU<af:popup id="contextMenu" contentDelivery="lazyUncached"           eventContext="launcher" launche...
INVOKING THE CONTEXT MENU<af:navigationPane ...........>  <af:commandNavigationItem ...............>     <f:attribute name...
USE EXISTING FUNCTIONALITY
CLOSE THIS TABpublic void closeThis(ActionEvent action) {    String id = getMenuInvokedOnTab();    List<String> tabsToRemo...
CLOSE OTHER TABSpublic void closeOthers(ActionEvent action) {    String id = getMenuInvokedOnTab();    List<String> tabsTo...
CLOSE ALLpublic void closeAll(ActionEvent action) {    List<String> tabsToRemove = new ArrayList();    for (DynTab t : get...
CLOSE ALL / CLOSE OTHERS
MOST RECENTLY USED (..HISTORY)
IMPLEMENTATION•   Record activities     – Use setPropertyListeners•   Historybean (session scope) that manages the collect...
CREATE THE BEAN      • Create History bean<managed-bean id=“1">   <managed-bean-name id=“2">                recentHistoryB...
INTERCEPT ACTIVITY<af:commandLink id="ot3" text="#{row.LastName}" action="edit"     actionListener="#{recentHistoryBean.ad...
RECORD ACTIVITYpublic void add(ActionEvent actionEvent) {   // Add event code here...   recentHistory.add(new HistoryEvent...
PERSIST ACTIVITYpublic void recordAndPersistHistoryEntry(HistoryEvent event) {  String statement =     "RECENT_HISTORY_MAN...
THE RESULT
DO YOU RECOGNIZE THIS ??
GOOGLE SEARCH
ADF QUERY COMPONENT ……
PREPARE THE DATABASE • Make sure that the HR user is allowed to use the   ctxsys.ctx_ddl packagegrant EXECUTE on CTXSYS.CT...
CREATE A SEARCH PACKAGEfunction get_emp_search_item ( p_rowid in rowid     ) returnvarchar2 asbegin   for b in (select e.f...
CREATE THE ORACLE TEXT INDICES-- Configure preferences...ctx_ddl.create_preference(emp_datastore, user_datastore);ctx_ddl....
THE BASE CLASSES• OracleTextSearchSupport:   • Converts the given user input (the search command):      <code>searchValue<...
CREATE THE MODEL PROJECT
CREATE THE MODEL PROJECT
VIEWCONTROLLER : A BEAN<managed-bean-name id="1">departmentsQuickSearch</managed-bean-name> <managed-bean-class id="4">   ...
VIEWCONTROLLER : A SUBFORM<af:subform id="s1" defaultCommand="cb7">    <af:panelGroupLayout id="pgl4" layout="horizontal" ...
VIEWCONTROLLER : SEARCH METHODprivate synchronized List<SelectItem> search(String searchValue) {  DCIteratorBinding iter =...
THE RESULT
REAL TIME UPDATES
THE CONCEPT
THE IMPLEMENTATION; THE DATABASEgrant change notification to <user>;
REGISTER FOR DBQRCN (STEP 1)public void startChangeNotification(){   DatabaseChangeRegistration dcr = null;   String query...
REGISTER FOR DBQRCN (STEP 2)// second step: add objects in the registration:    Statement stmt = conn.createStatement();((...
WHATS NEXT ….
SETUP ACTIVE DATA COMPONENTpublic void setupActiveData() {   ActiveModelContext context =          ActiveModelContext.getA...
SETUP THE ACTUAL UPDATEpublic void triggerDataUpdate(String message) {    this.message = message;    counter.incrementAndG...
IMPLEMENTATION IN THE PAGE <af:activeOutputText        value="#{pageFlowScope.trackChangesBean.updates}"        id="aot1" ...
THE RESULT
PATTERNS UNDER INVESTIGATION• Grouping Tabs• Drag and Drop Tabs in UI Shell   – dragSource and dropTarget•   Duplicating T...
PATTERNS UNDER INVESTIGATION•   Adding Sticky Notes    – dragSource and dropTarget    – Contextual events    – Concept : h...
RESOURCES
RESOURCES
SUMMARY
ADFHow to Bring Common UI Patterns to ADFLuc Bors, AMIS, The NetherlandsLuc.Bors@amis.nlLucBors@gmail.comFollow me on Twit...
Upcoming SlideShare
Loading in …5
×

How te bring common UI patterns to ADF

966 views

Published on

Deze presentatie is gegeven tijdens de KScope conferentie 2012

Spreker: Luc Bors
Titel: How to Bring Common UI Patterns to ADF
Onderwerp: Fusion Middleware - Subonderwerp: ADF


Eindgebruikers van bedrijfsapplicaties eisen dezelfde gebruikerservaring die ze kennen van bijvoorbeeld office applicaties en applicaties op het internet. Functies zoals bookmarking, favorieten en het werken met tabs wordt graag gezien in de dagelijkse werk. Het zoekmechanisme van Google, dat suggesties toont op basis van de ingevoerde tekst, is zo ´gewoon´ dat mensen dit in elke applicatie terug willen zien. Twitter en Facebook geven automatisch aan dat je nieuwe berichten hebt zonder dat je daar zelf eerst om moet vragen, dat gebruikers de normaalste zaak van de wereld vinden. Er zijn nog veel meer van deze UI patterns. In deze sessie leer je hoe een aantal van deze UI patterns in je ADF applicatie kunt inbouwen waardoor de eindgebruiker beschikking krijgt over bekende en vanzelfsprekende features. Dit zal leiden tot een snellere acceptatie van de applicatie en prettigere gebruikerservaring.

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
966
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
29
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

How te bring common UI patterns to ADF

  1. 1. ADFHow to Bring Common UI Patterns to ADFLuc Bors, AMIS, The NetherlandsWednesday, June 27, 2012ODTUG KScope 12San Antonio, Texas, USA
  2. 2. UI PATTERNS
  3. 3. FUSION APPS PATTERNS
  4. 4. RECOGNIZE THESE ?
  5. 5. RECOGNIZE THESE ?
  6. 6. TABBED NAVIGATION
  7. 7. TABBED NAVIGATION
  8. 8. CLOSE ALL / CLOSE OTHERS
  9. 9. CLOSE ALL / CLOSE OTHERS
  10. 10. CLOSE ALL / CLOSE OTHERS• e
  11. 11. CAN YOU DO THIS IN ADF ?
  12. 12. CREATE THE CONTEXT MENU<af:popup id="contextMenu" contentDelivery="lazyUncached" eventContext="launcher" launcherVar="source"><af:menu id="men1" text="#{source.attributes.menuInvokedOnTab}"> <af:commandMenuItem id="cmi1" text="close“ actionListener="#{viewScope.jhsDynTabContext.closeThis}"> <af:setPropertyListener from="#{source.attributes.menuInvokedOnTab}" to="#{viewScope.jhsDynTabContext.menuInvokedOnTab}" type="action"/> </af:commandMenuItem> <af:commandMenuItem id="cmi2" text="close others“ actionListener="#{viewScope.jhsDynTabContext.closeOthers}">……. </af:commandMenuItem> <af:commandMenuItem id="cmi3" text="close all“ actionListener="#{viewScope.jhsDynTabContext.closeAll}"> …………….. </af:commandMenuItem> </af:menu></af:popup>
  13. 13. INVOKING THE CONTEXT MENU<af:navigationPane ...........> <af:commandNavigationItem ...............> <f:attribute name="tabId" value="#{tab.id}"/> <af:clientListener method="showMenu" type="contextMenu"/> <af:clientAttribute name="menuInvokedOnTab" value="#{tab.id}"/> </af:commandNavigationItem></af:navigationPane >function showMenu(evt) { var popup = AdfPage.PAGE.findComponent("pt:contextMenu"); …………….. popup.show(hints); evt.cancel();}
  14. 14. USE EXISTING FUNCTIONALITY
  15. 15. CLOSE THIS TABpublic void closeThis(ActionEvent action) { String id = getMenuInvokedOnTab(); List<String> tabsToRemove = new ArrayList(); for (DynTab t : getActiveTabList()) { String x = t.getId(); if (id == x) { tabsToRemove.add(x); } } for (String t : tabsToRemove) { removeTab(t); }}
  16. 16. CLOSE OTHER TABSpublic void closeOthers(ActionEvent action) { String id = getMenuInvokedOnTab(); List<String> tabsToRemove = new ArrayList(); for (DynTab t : getActiveTabList()) { String x = t.getId(); if (id != x) { tabsToRemove.add(x); } } for (String t : tabsToRemove) { removeTab(t); }}
  17. 17. CLOSE ALLpublic void closeAll(ActionEvent action) { List<String> tabsToRemove = new ArrayList(); for (DynTab t : getActiveTabList()) { tabsToRemove.add(t.getId()); } for (String t : tabsToRemove) { removeTab(t); }}
  18. 18. CLOSE ALL / CLOSE OTHERS
  19. 19. MOST RECENTLY USED (..HISTORY)
  20. 20. IMPLEMENTATION• Record activities – Use setPropertyListeners• Historybean (session scope) that manages the collection of navigation events – Display Label, Entity Type and Primary Key – bean calls …• BusinessService to record event in database for this user – (Optional) Also remove events for deleted records!
  21. 21. CREATE THE BEAN • Create History bean<managed-bean id=“1"> <managed-bean-name id=“2"> recentHistoryBean</managed-bean-name> <managed-bean-class id=“3"> nl.amis.jsf.history.beans.RecentHistoryBean </managed-bean-class> <managed-bean-scope id=“3">session</managed-bean-scope></managed-bean>
  22. 22. INTERCEPT ACTIVITY<af:commandLink id="ot3" text="#{row.LastName}" action="edit" actionListener="#{recentHistoryBean.add}"> <af:setPropertyListener from="#{row.EmployeeId}“ to="#{recentHistoryBean.entityInstanceIdentifier}" type="action"/> <af:setPropertyListener from="#{row.LastName}“ to="#{recentHistoryBean.entityInstanceDisplayLabel}" type="action"/> <af:setPropertyListener from="#{EMP}" to="#{recentHistoryBean.entityType}" type="action"/></af:commandLink>
  23. 23. RECORD ACTIVITYpublic void add(ActionEvent actionEvent) { // Add event code here... recentHistory.add(new HistoryEvent(new oracle.jbo.domain.Date() , entityType , entityInstanceIdentifier , entityInstanceDisplayLabel)); HRServiceImpl hrAppMod = (HRServiceImpl) pageTemplateBc.getDataControl().getApplicationModule(); hrAppMod.recordAndPersistHistoryEntry(recentHistory.get(0));
  24. 24. PERSIST ACTIVITYpublic void recordAndPersistHistoryEntry(HistoryEvent event) { String statement = "RECENT_HISTORY_MANAGER.RECORD_AND_PERSIST_ENTRY(?,?,?,?)"; callStoredProcedure(statement, new Object[] {event.getEntityType() , event.getKey().toString() , event.getDisplayLabel(), null}); }
  25. 25. THE RESULT
  26. 26. DO YOU RECOGNIZE THIS ??
  27. 27. GOOGLE SEARCH
  28. 28. ADF QUERY COMPONENT ……
  29. 29. PREPARE THE DATABASE • Make sure that the HR user is allowed to use the ctxsys.ctx_ddl packagegrant EXECUTE on CTXSYS.CTX_DDL to HR
  30. 30. CREATE A SEARCH PACKAGEfunction get_emp_search_item ( p_rowid in rowid ) returnvarchar2 asbegin for b in (select e.first_name , e.last_name , e.email , e.phone_number , j.job_title from employees e left join jobs j using (job_id) where e.rowid = p_rowid) loop return b.first_name || || b.last_name || ( || b.email || , || b.phone_number || , || b.job_title || ); end loop;end get_emp_search_item;
  31. 31. CREATE THE ORACLE TEXT INDICES-- Configure preferences...ctx_ddl.create_preference(emp_datastore, user_datastore);ctx_ddl.set_attribute(emp_datastore, procedure , ot_search.create_emp_search_item); -- Create the indices... execute immediate create index emp_search_index on employees(last_name) indextype is ctxsys.context parameters (datastore emp_datastore wordlist wordlist lexer lexer stoplist stoplist sync (on commit));
  32. 32. THE BASE CLASSES• OracleTextSearchSupport: • Converts the given user input (the search command): <code>searchValue</code> to an Oracle Text search-string.• BaseViewObjectImpl • overrides getCriteriaItemClause(ViewCriteriaItem vci)• BaseViewDefImpl • implementation to provide the following custom properties on ViewObjects: • ORACLE_TEXT_SEARCH_ATTRIBUTE: To mark the column in which the seach info is queried • ORACLE_TEXT_INDEX_ATTRIBUTE: To mark the database column on which the index was defined in the database.
  33. 33. CREATE THE MODEL PROJECT
  34. 34. CREATE THE MODEL PROJECT
  35. 35. VIEWCONTROLLER : A BEAN<managed-bean-name id="1">departmentsQuickSearch</managed-bean-name> <managed-bean-class id="4"> adfplus.quicksearch.controller.bean.QuickSearchBean </managed-bean-class> <managed-bean-scope id="2">pageFlow</managed-bean-scope> <managed-property id=“8"> <property-name id=“10">iteratorBindingName</property-name> <property-class>java.lang.String</property-class> <value id="9">DepartmentsVO1Iterator</value> </managed-property> <managed-property id="11"> <property-name id="13">searchAttribute</property-name> <property-class>java.lang.String</property-class> <value id="12">DepartmentSearchString</value> </managed-property> <managed-property id="14"> <property-name id="15">searchIteratorBindingName</property-name> <property-class>java.lang.String</property-class> <value id="16">DepartmentsVO1IteratorQuickSearch</value> </managed-property>
  36. 36. VIEWCONTROLLER : A SUBFORM<af:subform id="s1" defaultCommand="cb7"> <af:panelGroupLayout id="pgl4" layout="horizontal" inlineStyle="margin:10px;"> <af:inputText label="Search" id="it2“ value="#{pageFlowScope.departmentsQuickSearch.searchValue}"> <af:autoSuggestBehavior suggestItems= "#{pageFlowScope.departmentsQuickSearch.suggestItems}" maxSuggestedItems="10"/> </af:inputText> <af:commandButton text="Search" id="cb7" action="#{pageFlowScope.departmentsQuickSearch.go}" partialSubmit="true"/> </af:panelGroupLayout></af:subform>
  37. 37. VIEWCONTROLLER : SEARCH METHODprivate synchronized List<SelectItem> search(String searchValue) { DCIteratorBinding iter = getSearchIteratorBinding(); applySearchCriteria(iter, searchAttribute, searchValue); translations.clear(); lastSuggestList = new ArrayList<SelectItem>(); lastSearchValue = searchValue; Row[] rows = iter.getAllRowsInRange(); for (Row row : rows) { String description = (String)row.getAttribute(searchAttribute); lastSuggestList.add(new SelectItem(description)); translations.put(description, row.getKey()); }return lastSuggestList; }
  38. 38. THE RESULT
  39. 39. REAL TIME UPDATES
  40. 40. THE CONCEPT
  41. 41. THE IMPLEMENTATION; THE DATABASEgrant change notification to <user>;
  42. 42. REGISTER FOR DBQRCN (STEP 1)public void startChangeNotification(){ DatabaseChangeRegistration dcr = null; String query = "SELECT * from DEPARTMENTS"; Properties prop = new Properties(); prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS ,"true");prop.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION ,"true"); try { dcr = conn.registerDatabaseChangeNotification(prop); RdbmsChangeEventListener listener = new RdbmsChangeEventListener(this); dcr.addListener(listener); ………..
  43. 43. REGISTER FOR DBQRCN (STEP 2)// second step: add objects in the registration: Statement stmt = conn.createStatement();((OracleStatement)stmt).setDatabaseChangeRegistration(dcr); ResultSet rs = stmt.executeQuery(query); while (rs.next()){} rs.close(); stmt.close();
  44. 44. WHATS NEXT ….
  45. 45. SETUP ACTIVE DATA COMPONENTpublic void setupActiveData() { ActiveModelContext context = ActiveModelContext.getActiveModelContext(); Object[] keyPath = new String[0]; context.addActiveModelInfo( this , keyPath , "activemessage"); System.out.println("add active bean as listener"); databaseNotificationProcessor.registerAsListener(this);}
  46. 46. SETUP THE ACTUAL UPDATEpublic void triggerDataUpdate(String message) { this.message = message; counter.incrementAndGet(); ActiveDataUpdateEvent event = ActiveDataEventUtil.buildActiveDataUpdateEvent( ActiveDataEntry.ChangeType.UPDATE, counter.get(), new String[0], null, new String[] { "activemessage" }, new Object[] { message }); System.out.println("fireActiveDataUpdate"); fireActiveDataUpdate(event); }
  47. 47. IMPLEMENTATION IN THE PAGE <af:activeOutputText value="#{pageFlowScope.trackChangesBean.updates}" id="aot1" visible="false"> <af:clientListener method="activeDataCallback" type="propertyChange"/></af:activeOutputText> <af:resource type="javascript"> activeDataCallback = function (event) { var button = AdfPage.PAGE.findComponentByAbsoluteId("pt1:r1:0:cb1"); button.setVisible(true); } </af:resource>
  48. 48. THE RESULT
  49. 49. PATTERNS UNDER INVESTIGATION• Grouping Tabs• Drag and Drop Tabs in UI Shell – dragSource and dropTarget• Duplicating Tabs – Restarting a new instance of a taskflow
  50. 50. PATTERNS UNDER INVESTIGATION• Adding Sticky Notes – dragSource and dropTarget – Contextual events – Concept : http://technology.amis.nl • Search for: adf-11g-dragn-drop-and-contextual-events/
  51. 51. RESOURCES
  52. 52. RESOURCES
  53. 53. SUMMARY
  54. 54. ADFHow to Bring Common UI Patterns to ADFLuc Bors, AMIS, The NetherlandsLuc.Bors@amis.nlLucBors@gmail.comFollow me on Twitter : @lucb_Wednesday, June 27, 2012ODTUG KScope 12San Antonio, Texas, USA

×