Please disable your adblock and script blockers to view this page

Search this blog

Monday, 9 February 2015

Custom selection listener for af:listView, Invoke selectionListener programmatically

In the last post (Better UI for data collection using af:listView, Enable selection in ADF Faces List component ) about af:listView, we saw that how can we present data collection in a better way using af:listView and enable selection using EL (same as used for af:table)

Now in this post i will describe about defining custom selection listener for af:listView
Suppose you have to do some task on selection of an item in list other than making it current row, for this you have to override default selection listener and define own custom selection listener in managed bean
So next step is to define a method in managed bean for handling selection event of af:list view



  • Select af:listView, goto properties and click on edit menu of selectionListener property and create a method in managed bean



  • now see what we have to do in custom selection listener, first invoke default selection listener EL (#{bindings.Departments1.collectionModel.makeCurrent}) to make selected row as current and then get current row from iterator as selected row is now current row
    See the managed bean code -

  • //Import these packages
    
    import javax.el.ELContext;
    import javax.el.ExpressionFactory;
    import javax.el.MethodExpression;
    import javax.el.ValueExpression;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.context.FacesContext;
    
    import oracle.jbo.Row;
    
    import org.apache.myfaces.trinidad.event.SelectionEvent;   
    
    
     /**
         * Programmatic invocation of a method that an EL evaluates to.
         *
         * @param el EL of the method to invoke
         * @param paramTypes Array of Class defining the types of the parameters
         * @param params Array of Object defining the values of the parametrs
         * @return Object that the method returns
         */
        public static Object invokeEL(String el, Class[] paramTypes, Object[] params) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            ELContext elContext = facesContext.getELContext();
            ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
            MethodExpression exp = expressionFactory.createMethodExpression(elContext, el, Object.class, paramTypes);
    
            return exp.invoke(elContext, params);
        }
    
        /**
         * Programmatic evaluation of EL.
         *
         * @param el EL to evaluate
         * @return Result of the evaluation
         */
        public static Object evaluateEL(String el) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            ELContext elContext = facesContext.getELContext();
            ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
            ValueExpression exp = expressionFactory.createValueExpression(elContext, el, Object.class);
    
            return exp.getValue(elContext);
        }
    
        /**Custome Selection Listener for af:listView
         * @param selectionEvent
         */
        public void listSelectionListener(SelectionEvent selectionEvent) {
            //invoke this EL to set selected row as current row, if it is not invoked then first row will be current row
            invokeEL("#{bindings.Departments1.collectionModel.makeCurrent}", new Class[] { SelectionEvent.class }, new Object[] {
                     selectionEvent });
            // get the selected row , by this you can get any attribute of that row
            Row selectedRow = (Row) evaluateEL("#{bindings.Departments1Iterator.currentRow}");
            FacesMessage msg = new FacesMessage(selectedRow.getAttribute("DepartmentName").toString());
            msg.setSeverity(FacesMessage.SEVERITY_INFO);
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }
    

  • Now run application and check

Download Sample ADF Application here
Thanks , Happy Learning :)

Friday, 6 February 2015

Better UI for data collection using af:listView, Enable selection in ADF Faces List component

af:listView is a new component introduced in Jdev 12C to show tabular data (rows of a collection), it uses same configuration as af:table
In this post i will be describing- how to create af:listView using ADF business component and  how we can enable selection in af:listView

Let's start
How to create af:listView using ADF BC-
  • Created a Fusion Web Application and prepared model using Departments table of HR Schema


  • drop Departments viewObject on page from DataControl as ADF List View




    Configuration Wizard for List is opened, set the appropriate layout


    Set the value binding that we want to show on page


    After this we can customize layout on page also, we can change color, style width etc;
    see XML source of af:listView-

    <af:listView value="#{bindings.Departments1.collectionModel}" var="item"
                                 emptyText="#{bindings.Departments1.viewable ? 'No data to display.' : 'Access Denied.'}"
                                 fetchSize="#{bindings.Departments1.rangeSize}" id="lv1">
                        <af:listItem id="li1">
                            <af:panelGroupLayout layout="horizontal" id="pgl1">
                                <f:facet name="separator">
                                    <af:spacer width="10" id="s1"/>
                                </f:facet>
                                <af:outputFormatted value="#{item.bindings.DepartmentId.inputValue}" id="of1"
                                                    inlineStyle="font-weight:bold;font-size:medium;color:red;">
                                    <af:convertNumber groupingUsed="false"
                                                      pattern="#{bindings.Departments1.hints.DepartmentId.format}"/>
                                </af:outputFormatted>
                                <af:outputFormatted value="#{item.bindings.DepartmentName.inputValue}" id="of2"
                                                    inlineStyle="font-weight:bold;font-size:small;color:navy;"/>
                            </af:panelGroupLayout>
                            <af:panelGroupLayout id="pgl2">
                                <af:outputLabel value="Manager id" id="ol1"/>
                                <af:outputFormatted value="#{item.bindings.ManagerId.inputValue}" id="of3">
                                    <af:convertNumber groupingUsed="false"
                                                      pattern="#{bindings.Departments1.hints.ManagerId.format}"/>
                                </af:outputFormatted>
                                <af:spacer width="10" height="10" id="s2"/>
                                <af:outputLabel value="Location Id" id="ol2"/>
                                <af:outputFormatted value="#{item.bindings.LocationId.inputValue}" id="of4">
                                    <af:convertNumber groupingUsed="false"
                                                      pattern="#{bindings.Departments1.hints.LocationId.format}"/>
                                </af:outputFormatted>
                            </af:panelGroupLayout>
                        </af:listItem>
                    </af:listView>
    


    and how it looks on page- hmmm better than af:table


  • By default adf listView doesn't support selection, you can see Selection property is set to none. it shares same configuration as af:table , you can see that value property is bound to #{bindings.Departments1.collectionModel} and attributes are populated using variable reference of this collection


  • To enable selection just set Selection to single and in selectionListener property of list set #{bindings.Departments1.treeModel.makeCurrent}




  • Now Run this application and check, single selection is enabled
 Thanks, happy learning :)

Tuesday, 3 February 2015

ADF Basics: Set multiple LOV's on attribute and conditionally switch using LOV Switcher

This post is about a very basic and common use case
Suppose we have to show different values in our List depending on some condition but all values must be stored in same attribute so for this type of requirement ADF BC framework provides concept of LOV Switcher
Framework allows us to define multiple LOV on same attribute, I hope you all know about defining LOV(List of Values) so move ahead and see how to use lov switcher

 See the implementation part-
  • Created a Fusion Web Application and a viewObject to show LOV on viewport (Used dual to create view object for this example , you can use use your own)





  • Created 2 more viewObject to apply LOV on first viewObject's attribute, One ViewObject is for Departments and other one is for Employees


  • Open dual viewObject select LovAppl attribute and goto ListOfValues tab and add both LOV
    For Department - DepartmentId is List Attribute and DepartmentName will be shown on UI


  • For Employees- EmployeeId is List Attribute and FirstName,LastName will be shown on UI



  • Now click on green plus icon of List Of Values Switcher and add a transient attribute , this will be further used to switch lov on base of some condition


  • So created LovSwitcher attribute , and remember this switcher attribute value should be one of the LOV Name that are applied on attribute.
    Here i am using a condition - if LovType attribute of Dual viewObject is 'D' the LovAppl should show Departments Lov and if it is 'E' then LovAppl should show Employees Lov
    For this i have written expression for lov switcher attribute
    LovType=='D' ? 'LOV_LovAppl' : LovType=='E' ? 'LOV_LovAppl1' : null


  • Now run Application Module and check it


Thanks , Happy Learning :)

Thursday, 22 January 2015

Show uploaded file (pdf/text/html/xml/image) content on page -Oracle ADF

Hello all
In previous post
Uploading and downloading files from absolute server path in Oracle ADF (12.1.3)
we saw that how can we upload any file to absolute server path and download same from there.
Uploading part is done using simple java code to write file to specified folder and downloading part is done using <af:fileDownloadActionListener>

Now in this post i am going to show that how can we display a file on page directly without downloading it.
So for this i am using same sample application that i have used in previous post , you can download it from here



See the additional steps to show file content on page-
  • Create a servlet to parse file into output stream , this output stream will be used to show file content further.
    To create servlet right click on viewController project select New--->From Gallery-->Web Tier-->Servlet




  • See servlet source code to parse file into outputStream

  • import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class PreviewFileServlet extends HttpServlet {
        private static final String CONTENT_TYPE = "text/html; charset=UTF-8";
    
        public void init(ServletConfig config) throws ServletException {
            super.init(config);
        }
    
        /**
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String path = (request.getParameter("path"));
    
            OutputStream os = response.getOutputStream();
            //If path is null
            if (path.equalsIgnoreCase("No")) {
                path = "D:\\Document\\ItemImage\\Item.jpg";
            }
            if (request.getParameter("path") == "") {
                path = "D:\\Document\\ItemImage\\Item.jpg";
            }
            InputStream inputStream = null;
    
            try {
                File outputFile = new File(path);
                inputStream = new FileInputStream(outputFile);
                BufferedInputStream in = new BufferedInputStream(inputStream);
                int b;
                byte[] buffer = new byte[10240];
                while ((b = in.read(buffer, 0, 10240)) != -1) {
                    os.write(buffer, 0, b);
                }
    
            } catch (Exception e) {
    
                System.out.println(e);
            } finally {
                if (os != null) {
                    os.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
    
            }
        }
    }
    

  • Now open page in editor and drop an af:inlineFrame from component palette . inlineFrame is used to create a frame to show any external page or document just like as HTML iframe , it is loaded from source attribute
    So here i am using servlet as source attribute for this inlineFrame

  • <af:inlineFrame id="if2"
                                                        source="/previewfileservlet?path=#{bindings.Path.inputValue == null ? 'No' : bindings.Path.inputValue}"
                                                        inlineStyle="height:350px;width:800px;" sizing="preferred"/>
    

    here path of document is added to pageDef bindings that is passed to servelt as parameter

  • Now run this application and check it

    View Text File-
          View PDF File-


Thanks, Happy Learning :)

Post Related to file handling in Oracle ADF- 

Show saved file (pdf/text/html/xml/image) content on page from database (BLOB) in ADF Application
Uploading and showing image file from absolute server path -Orace ADF
Exporting viewObject data in text file using af:fileDownloadActionListener in Oracle ADF (12.1.3)
Creating pdf file using Apache PDFBox API in ADF Faces and opening it in new window -Oracle ADF
Download file from url using Oracle ADF & Java- Download Manager
Reading html source of a webpage (url) using Oracle ADF (af:richTextEditor) & Java

Friday, 16 January 2015

Setting view object bind variable (Override bindParametersForCollection, prepareRowSetForQuery, executeQueryForCollection )

Hello All,
This post is about a very basic question- How to set bind variable of a view object ?
and there are multiple posts about it that describes multiple ways to do this
Using setNamedWhereClause
Using VariableValueManager 
Using setter method in VOImpl class

But Sometimes we can not assign bind variable value in declarative way for first time execution as value source for bind variable is fixed but it's value may change at runtime from n number of events



So for this type of requirement we can set bind variable's value in such a way so that we need not to write code everywhere to set changed value.
See how can we do this -

  • Create a Fusion Web Application and prepare model using Departments table of HR Schema




  • Open Departments viewObject add a bind variable in it's query , this bind variable is further used to set value and filter result set





  • Create Java class for Department view object, goto java tab of Departments VO and click on edit icon of Java Classes and select "Generate ViewObject Class"





  • Now we can set bind variable's value by overriding 3 methods of DepartmentVOImpl class

1. Overriding bindParametersForCollection in ViewObject java class -

This method is used to set bind variable's value by framework, framework supplies an array of all bind variable to this method We can override this method to set value of bind variable ,
Open DepartmentVOImpl class and click on override methods icon on top of editor
It will open a window that consist all methods , search by name and click on ok



See the code in DepartmentVOImpl-


    /**@override Method to set bind variable's value at runtime (Framework Internal Method)
     * @param queryCollection
     * @param object
     * @param preparedStatement
     * @throws SQLException
     */
    protected void bindParametersForCollection(QueryCollection queryCollection, Object[] object,
                                               PreparedStatement preparedStatement) throws SQLException {
        for (Object bindVar : object) {
            // Iterate over bind variable set and find specific bind variable
            if (((Object[])bindVar)[0].toString().equals("BindDeptId")) {
                // set the bind variable's  value
                ((Object[])bindVar)[1] = 100;

            }
        }
        super.bindParametersForCollection(queryCollection, object, preparedStatement);

    }

2. Overriding prepareRowSetForQuery in ViewObject java class -

This method (introduce in 11.1.1.5 release) executes before bindParametersForCollection , same thing can also be done in this method 
Override method in Impl class 


See the Code in DepartmentsVOImpl-


    /**@override Method to prepare RowSet for execution(Framework Internal Method)
     * @param viewRowSetImpl
     */
     public void prepareRowSetForQuery(ViewRowSetImpl viewRowSetImpl) {
        //Set Bind Variable's value 
        viewRowSetImpl.ensureVariableManager().setVariableValue("BindDeptId", 100);
        super.prepareRowSetForQuery(viewRowSetImpl);
    } 

3. Overriding executeQueryForCollection in ViewObject java class -


This method invokes just before framework executes rowset , avoid setting bind varibale in this method because it is not called before some methods as getEstimatedRowCount(), So whenever you try to get rowcount it will return wrong values 
still it works and sets the bind varible value and executes rowset, again override method



See the Code in DepartmentsVOImpl-


    /**Method to excute viewObject rowSet(Framework Internal Method)
     * @param object
     * @param object2
     * @param i
     */
    protected void executeQueryForCollection(Object object, Object[] object2, int i) {
        for (Object bindVar : object2) {
            // Iterate over bind variable set and find specific bind variable
            if (((Object[])bindVar)[0].toString().equals("BindDeptId")) {
                // Set the bind variable value
                ((Object[])bindVar)[1] = 100;

            }
        }
        super.executeQueryForCollection(object, object2, i);
    }

Now use anyone of these methods to set bind variable value and run application module, check result
It is showing data for DepartmentId 100.

Thanks, Happy Learning :)