Вы находитесь на странице: 1из 12

Blog > Oracle ADF >

ADF Select Many Shuttle


September 30th, 2010 | Posted by Bogdan Petridean in Oracle ADF | 13 Comments In this post we will use the af:selectManyShuttle ADF component in order to handle insert, view, update and delete data in a faster and more elegant way. ADFSelectManyShuttle sample application implemented using JDeveloper IDE version 11.1.1.3.0 can be downloaded from HERE The application uses an extended version of the HR database contains a new table named LOCATION_DEPARTMENTS - which creates a many-to-many relationship between LOCATIONS and DEPARTMENTS tables and has been packed as an sql script HRShuttleScript.sql and stored inside the Database_Script directory within the ADFSelectManyShuttle application. HRShuttleScript.sql script alone can be downloaded from HERE Next, use JDeveloper IDE to create a new Fusion Web Application and follow the steps below:

Model Project
Create a connection to HR database and use it to generate the Locations, Departments and LocationDepartments entities and view objects: New -> Business Tier -> ADF Business Components -> Business Components from Tables -> select LOCATIONS, DEPARTMENTS and LOCATION_DEPARTMENTS tables > Entity and Updatable View Object If not automatically generated you must create the following associations and view links: LocationsToLocationDepartmentsVL - will be used in order to nest a LocationDepartmentsVO inside a LocationsVO (will give us all the departments for a given location):

Optional: LocationDepartmentsToDepartmentsVL will be used to nest a DepartmentsVO inside a LocationDepartmentsVO (will enable us, by using Groovy expression, to get the Department Name inside the LocationDepartmentsVO):

Open AppModule and use the above View Links to create the following structure:

Optional: Next, we will use Groovy Expression Language to add 2 new transient attributes to our view objects: 1. Open LocationDepartmentsVO and add DepartmentName attribute - representing the name of the department - and use Groovy to calculate its value:

2.- Open LocationsVO and add Departments attribute - representing the number of departments for the current location - and use Groovy to calculate its value:

Hint: The paragraphs denoted as optional are not necessary, but they will be used by the tree table in order to show to the user that the af:selectManyShuttle component works as expected.

ViewController Project
Business
Create a new java class, name it Shuttle - generic helper shuttle class and use the code below for it: ?

01public class Shuttle { public Shuttle() { 02 } 03 04 /**

05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

* Given an iterator name, a value attribute name and a display attribute name * this method will invoke selectItemsForIterator method to return a List of Selec * * @param iteratorName - parent VO iterator * @param valueAttrName * @param displayAttrName * @return */ public static List<SelectItem> getAll(String iteratorName, String valueAttrName, String displayAttrName) { return ADFUtils.selectItemsForIterator(iteratorName, valueAttrName, displayAttrName); }

/** *Given an iterator name and an attribute name this method will return a List of i * * @param iteratorName - nested VO iterator * @param attrName * @return */ public static List getSelected(String iteratorName, String attrName) { List selected = new ArrayList(); DCIteratorBinding iterator = ((DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry() Row[] rowSet = iterator.getAllRowsInRange(); for (Row r : rowSet) { selected.add(r.getAttribute(attrName)); } return selected; }

/** * * @param selectedValues * @param pkAttName - this attribute should be declared in page bindings * @param fkIteratorName - nested VO iterator * @param fk1AttName * @param fk2AttName * @param deleteOpName - delete operation should be defined in page bindings * @param createInsertOpName - createInsert operation should be defined in page bi */ public static void setSelected(List selectedValues, String pkAttName, String fkIteratorName, String fk1AttName, String fk2AttName, String deleteOpName, String createInsertOpName) { if (selectedValues == null) selectedValues = new ArrayList(0); DCBindingContainer dcbindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry(); Object pkAtt = ADFUtils.getBoundAttributeValue(pkAttName); DCIteratorBinding iterator = dcbindings.findIteratorBinding(fkIteratorName); OperationBinding deleteOp = dcbindings.getOperationBinding(deleteOpName); OperationBinding createInsertOp = dcbindings.getOperationBinding(createInsertOpName); Row[] rowSet = iterator.getAllRowsInRange();

55 56 57 58 59 60 61 62 63 64 65 66 67 68} 69 70 71 72 73 74 75 76 77 78 79 80 81 82

for (Row row : rowSet) { Object fk2Att = row.getAttribute(fk2AttName); if (!selectedValues.contains(fk2Att)) { iterator.setCurrentRowWithKey(row.getKey().toStringFormat(true)); deleteOp.execute(); } else { selectedValues.remove(fk2Att); } } for (Object val : selectedValues) { createInsertOp.execute(); Row row = iterator.getCurrentRow(); row.setAttribute(fk2AttName, val); row.setAttribute(fk1AttName, pkAtt); } }

Create a new java class, name it Business it will use the generic static methods of the Shuttleclass defined above and will contain the business for our departments shuttle: get all departments, get selected departments and set department/s as selected and/or available. All methods implemented within this bean will be presented with respect to the visual component for which they provide service. Next, open adfc-config.xml -> Overview -> Managed Beans and set Business bean scope to request as presented in the below image:

User Interface
Create a new JSF page, name it main.jspx and follow the steps below: Open Data Controls -> AppModuleDataControl and drag&drop the LocationsVO as a Single Selection, Table or Tree into the newly created main.jspx page:

In this example we shall use the Tree because we want to display for each location the number of departments it contains and list the department names as first degree children visible when the location node is expanded. Go to main.jspx Bindings and make sure that: 1. LocationsVOIterator, LocationDepartmentsVOIterator and DepartmentsVOIterator are defined within the Executables panel box. 2. CreateInsert operation and a Delete operation are defined for theLocationDepartmentsVOIterator. 3. You also need to add a new attribute value binding for the LocationId of LocationsVOIterator. Your Bindings should look as follows:

Now, add an af:selectManyShuttle component into the main.jspx page and follow the steps below to configure it: 1. Select the af:selectManyShuttle and within the Value field which must contain the list of selected departments write #{Business.selectedDepartments}. The selectedDepartments getter and setter methods are defined within the Business: ?

01 02 03 04 05 06 07 08

public List getSelectedDepartments() { return Shuttle.getSelected("LocationDepartmentsVOIterator", "DepartmentId"); } public void setSelectedDepartments(List selectedValues) { Shuttle.setSelected(selectedValues, "LocationId", "LocationDepartmentsVOIterator", "LocationId", "DepartmentId", "Delete", "CreateInsert");

09 10

2. Expand the af:selectManyShuttle component nest inside it if not already there af:selectItems component which will contain the list of all departments. Within the Value field of the f:selectItems component set #{Business.allDepartments}. allDepartments attribute (actually the getter method) is defined in Business bean: ?

1 2 3 4

public List<SelectItem> getAllDepartments() { return Shuttle.getAll("DepartmentsVOIterator", "DepartmentId", "DepartmentName"); }

3. Set the PartialTriggers for the shuttle component to point to the locations tree table:

Finally, add a new af:commandButton component into the page and drag from Data Controls theCommit operation and drop it onto the button. You are done!

Running the sample application


Open ADFSelectManyShuttle OFM application in your JDevelopper IDE, navigate to main.jspx page and run it. After the application has been successfully deployed the following page will be loaded into your browser:

Now, for each location we can see the details plus the number of departments that location contains. If we expand(right click -> Expand or click onto City expand/collapse item) a location with more that zero departments all the departments are displayed for the user to view. For every selection we make in the tree table the select many shuttle is updated. Now, select a location from the tree table and use the shuttle to add or remove departments from it; after you are done click Save button and double-check that your modifications have been successfully saved by looking within the tree table. You will also notice that the Available section of the shuttle will always contain all selected, so no duplicates:

Tags: select many, select many shuttle, shuttle

13 Responses to ADF Select Many Shuttle


1. Matt H October 1, 2010 at 4:06 AM

Awesome job folks! This is almost exactly what I was looking for.. that being a selectOrderShuttle example but I can figure it out from what youve done. I was stumped on how to save the data once its been arranged by the user. I assume the Commit action calls the setSelectedDepartments method in the backing bean? Also, the use of transient attributes with Groovy derived values to display additional detail data in the master tree is a neat additional feature. Reply

Bogdan Petridean October 1, 2010 at 10:51 AM Thank you Matt, The setSelectedDepartments setter method is handled by the shuttle component and it Inserts/Deletes department into/from LocationDepartmentsVO. The transaction is commited when Save button is pressed. So, in the above example you can add/remove departments to/from multiple locations and when save is pressed they will all be commited.

2.

Matt H October 1, 2010 at 5:16 AM

Sorry for the double post before. Theres something Id like to add to your sample. That being, instead of using your ADFUtils.selectItemsForIterator method, use the following to generate a ToolTip with a description, if you have one, for the items in the shuttle component: /** For a given Iterator, returns a List of SelectItem * objects containing the value, Name and ToolTip. The * value is what is represented underneath * the data model, the Name is what will be displayed in * the selection list and the ToolTip will be used for * display when hovering over an item in the * selection list. * @param iteratorName * @param valueAttrName * @param displayAttrName * @param displayAttrToolTip * @return */ public static List getSelectItemsFromIterator(String iteratorName, String valueAttrName, String displayAttrName, String displayAttrToolTip) { BindingContext bc = BindingContext.getCurrent(); DCBindingContainer binding = (DCBindingContainer)bc.getCurrentBindingsEntry(); DCIteratorBinding iter = binding.findIteratorBinding(iteratorName); List selectItems = new ArrayList(); for (Row r : iter.getAllRowsInRange()) { selectItems.add( new SelectItem(r.getAttribute(valueAttrName), (String)r.getAttribute(displayAttrName), (String)r.getAttribute(displayAttrToolTip))); } return selectItems; } Reply

Bogdan Petridean October 1, 2010 at 10:57 AM Thank you Matt, I will try it. Regards, bogdan

3.

Dino Kantardzic October 1, 2010 at 3:46 PM

As I said in my thread great example but the Commit doesnt work for me, it gives me a null pointer exception, if anyone has an idea why here is some code (the backing bean) public BindingContainer getBindings() { if (this.bindings == null) { FacesContext fc = FacesContext.getCurrentInstance(); this.bindings = (BindingContainer)fc.getApplication().evaluateExpressionGet(fc, #{bindings} , BindingContainer.class); } return this.bindings; } public List getAllDepartments() { return MultiShuttle.getAll(AdslView1Iterator, AdslId, TipKonekcije); } public List getSelectedDepartments() { return MultiShuttle.getSelected(Adsl_TehOprVeza_View2Iterator, AdslId); } public void setSelectedDepartments(List selectedValues) { MultiShuttle.setSelected(selectedValues, TehOprId, Adsl_TehOprVeza_View2Iterator, TehOprId, AdslId, Delete, CreateInsert); } The jspx page The commit button Reply 4. Dino Kantardzic October 1, 2010 at 3:49 PM

I am not able to post some code here for some reason but I have it all on this thread: http://forums.oracle.com/forums/thread.jspa?threadID=1359249&stqc=true Reply

Bogdan Petridean October 1, 2010 at 6:04 PM It would be faster if you would pack up your application and send it to me. Regards, bogdan.

5.

Horatiu February 22, 2011 at 3:33 PM

HiGreat post and very useful. I have one question for you: At this step (Optional ones) 2.- Open LocationsVO and add Departments attribute representing the number of departments for the current location and use Groovy to calculate its value: can instead of LocationDepartmentsVO.count(DepartmentId) which counts the number of Departments for each Location to display the names of that departments (according to DepartmentName) How can be this done, preferable without using java classes that should interogate DB, or maybe some additionals inner join between departments and location? If you ca give me a hinti will appreciate. Thanks, Horatiu Reply

Bogdan Petridean February 22, 2011 at 5:45 PM Hi Horatiu, All the above can be done by using Groovy EL. Actually in this case you do not have to do any extra work because LocationDepartmentsVO, which contains an attribute called Department Name, is exactly what you need. To check this just Run AppModule and select LocationsVO -> LocationsToLocationDepartmentsVL and than use the navigation arrows to change the location; you will notice that when a location that has any departments is selected the departments are listed below. You can find more info about Groovy EL here: http://www.gebs.ro/blog/oracle/adf-bc-viewlink-viewlinkaccessor-and-groovy/ If you encounter any problems Im here. Regards, Bogdan.

Вам также может понравиться