Showing posts with label code snippets. Show all posts
Showing posts with label code snippets. Show all posts

Wednesday, 21 October 2015

Get the size of a collection in EL using JSTL

Although the java.util.Collection interface defines a size method, it does not conform to the JavaBeans component design pattern for properties and so cannot be accessed by using the JSP expression language.

The JSTL length function can be applied to any collection supported by the c:forEach and returns the length of the collection.

When applied to a String, it returns the number of characters in the string.

Add the JSTL functions namespace to the page/fragment:

xmlns:fn="http://java.sun.com/jsp/jstl/functions"

then you can use the length expression:

rendered="#{fn:length(bindings.actuatorList.allRowsInRange) > 0}">

Other useful JSTL functions:

  • toUpperCase, toLowerCase: Changes the capitalization of a string 
  • substring, substringBefore, substringAfter: Gets a subset of a string 
  • trim: Trims white space from a string 
  • replace: Replaces characters in a string 
  • indexOf, startsWith, endsWith, contains, containsIgnoreCase: Checks whether a string contains another string 
  • split: Splits a string into an array 
  • join: Joins a collection into a string 
  • escapeXml: Escapes XML characters in a string

Using parametric Resource Bundle keys in EL expressions

Sometimes we have the need of defining parametric keys in a resource bundle file, to make the EL expressions in our ADF pages/fragments more readable and maintainable.

For this purpose, ADF provides EL functions which support both positional and named parameters.

  • af:formatString : for formatting a string with a positional parameter. 
  • af:formatString2 : for formatting a string with two positional parameters.
  • af:formatString3 : for formatting a string with three positional parameters.
  • af:formatString4 : for formatting a string with four positional parameters. 
  • af:formatNamed : for formatting a string with a named parameter. 
  • af:formatNamed2 : formatting a string with two named parameters. 
  • af:formatNamed3 : for formatting a string with three named parameters. 
  • af:formatNamed4 : for formatting a string with four named parameters. 

If we use named parameters in our resource bundles:

SCAN_DURATION_VALUE={HOURS} hours, {MINS} minutes 

We can use the formatNamed functions:

<af:outputText value="#{af:formatNamed2(myBundle.SCAN_DURATION_VALUE,
                                                 'HOURS', varHours, 
                                                 'MINS', varMins)}"/>

If we use positional parameters instead:
 
TASK_CURRENT_STEP=Currently executing step {0} of {1}

Then we can use the formatString functions:

<af:outputText value="#{af:format2(myBundle.TASK_CURRENT_STEP, var1, var2)}"/>

In alternative, we can use the JSF outputformat component, which uses a positional approach:
  
<h:outputFormat value="#{myBundle.TASK_CURRENT_STEP}" id="of2">
     <f:param value="#{pageFlowScope.var1}" id="p1"/>
     <f:param value="#{pageFlowScope.var2}" id="p3"/>
</h:outputFormat>

Implement a custom autosuggest filter for an ADF table

The purpose is to create a custom filter with autosuggestion feature on an ADF table column.

The idea is to have a couple of buttons in the table header to make the filter visible, and to disable and clear the filter itself:


After the filter is enabled, the text box appears, and as soon as the user starts typing, the autosuggestion kicks in:



This is what we need on the page/fragment:

A button to activate the filter (i.e. make the filter visible):

<af:commandButton text="Filter"
   id="cbFilter" rendered="true" partialSubmit="true"
   disabled="#{pageFlowScope.filter}" styleClass="btn">
 <af:setActionListener from="true" to="#{pageFlowScope.filter}"/>
</af:commandButton>

A button to deactivate and clear the filter:

<af:commandButton text="#{vehicleBundle.SELECTIVE_TABLE_FILTER_DISABLE}"
     id="cbDFilter" rendered="true"
     partialSubmit="true"
     actionListener="#{viewScope.vehicleBean.resetTableFilter}"
     disabled="#{!pageFlowScope.filter}"
     styleClass="btn">
  <af:setActionListener from="false"
      to="#{pageFlowScope.filter}"/>
</af:commandButton>

This is the table containing the filter: in the column we want to filter, we have an af:inputText component with autosuggest behavior operation, and two buttons to perform the filtering and clear the filter.
<af:table value="#{bindings.vehicleList1.collectionModel}" var="row"
     rows="#{bindings.vehicleList1.rangeSize}" fetchSize="5"
     varStatus="vs" partialTriggers=":cbDFilter :cbFilter"
     filterModel="#{bindings.vehicleListQuery.queryDescriptor}"
     queryListener="#{bindings.vehicleListQuery.processQuery}"
     filterVisible="#{pageFlowScope.filter}" id="listVehicles" [ . . . ]>
[ . . .]
<af:column filterable="true" filterFeatures="caseInsensitive"
     headerText="#{vehicleBundle.VEHICLE_DESC}" id="cVD">
 <f:facet name="filter">
  <af:panelGroupLayout id="pgAS" layout="vertical">
    <af:outputText value="#{vehicleBundle.FILTER_VEHICLES}" id="oFMsg"/>
    <af:panelGroupLayout id="pgFL" layout="horizontal">
    <af:inputText id="itFL"
         value="#{vs.filterCriteria.vehicleDescription}"
         autoSubmit="true" usage="search">
     <af:autoSuggestBehavior suggestItems="#{viewScope.vehicleBean.suggestedVehicles}"/>
    </af:inputText>
    <af:commandButton partialSubmit="true" id="cbexecute" text="Filter"/>
    <af:commandButton partialSubmit="true" id="cbclear" text="Clear"
          actionListener="#{viewScope.vehicleBean.resetTableFilter}"/>
    </af:panelGroupLayout>
  </af:panelGroupLayout>
 </f:facet>
</af:column>

In this case, we need the item type returned from the iterator to expose an attribute called 'vehicleDescription'.
  Since the table is supposed to show a collection of Vehicle objects, the Vehicle class needs to have a 'vehicleDescription' property (or a getter method called 'getVehicleDescription').

  So the page definition for this page/fragment will contain something like this:

<tree IterBinding="vehiclesIterator" id="vehicleList1">
      <nodeDefinition DefName="com.test.Vehicle"
                      Name="vehicleList10">
        <AttrNames>
          <Item Value="id"/>
          <Item Value="vciIdentifier"/>
          [. . .]
          <Item Value="vehicleDescription"/>
        </AttrNames>
      </nodeDefinition>
    </tree>

 [. . .]
 
 <searchRegion Binds="vehiclesIterator" Criteria=""
     Customizer="oracle.jbo.uicli.binding.JUSearchBindingCustomizer"
     id="vehicleListQuery"/>
 
Here are the methods needed:
public List suggestedVehicles(FacesContext facesContext,
                                 AutoSuggestUIHints autoSuggestUIHints) {
        // Add event code here...
        List<SelectItem> suggestions =
            autoSuggestIterator("vehiclesIterator",
                                         "vehicleDescription",
                                         autoSuggestUIHints.getSubmittedValue());
        return suggestions;
    }

    public void resetTableFilter(ActionEvent actionEvent) {
        // Add event code here...
        resetTableFilter("listVehicles");
    }
 
    public List<SelectItem> autoSuggestIterator(String iterator, String listValue, String input){
        // Add event code here...
        DCIteratorBinding binding = ADFUtils.findIterator(iterator);
        int rangeSize = binding.getRangeSize();
        binding.setRangeSize(1000);
        List suggestionList = ADFUtils.attributeListForIterator(iterator, listValue);
        List<SelectItem> suggestions = new ArrayList<SelectItem>();

        for (int i = 0; i < suggestionList.size(); i++) {
            if (suggestionList.get(i).toString().toUpperCase().contains(input.toUpperCase())) {
                suggestions.add(new SelectItem(suggestionList.get(i)));
            }
        }
        binding.setRangeSize(rangeSize);
        return suggestions;
    }
 
   public List attributeListForIterator(DCIteratorBinding iter,
                                         String valueAttrName) {
        List attributeList = new ArrayList();
        for (Row r : iter.getAllRowsInRange()) {
            attributeList.add(r.getAttribute(valueAttrName));
        }
        return attributeList;
    }
 
   public void resetTableFilter(String tableId) {

        UIComponent uiComponent = JSFUtils.findComponentInRoot(tableId);
        RichTable table = (RichTable)uiComponent;

        FilterableQueryDescriptor queryDescriptor =
            (FilterableQueryDescriptor)table.getFilterModel();
        if (queryDescriptor != null &&
            queryDescriptor.getFilterCriteria() != null) {
            queryDescriptor.getFilterCriteria().clear();
            table.queueEvent(new QueryEvent(table, queryDescriptor));
        }
    }

Tuesday, 15 April 2014

Redirect to servlet URL in a new browser window

      
Object contextPath = JSFUtils.resolveExpression("#{request.contextPath}");
String servletPath = contextPath + "/livedata";
try {
    FacesContext context = FacesContext.getCurrentInstance();
    ExtendedRenderKitService erks = Service.getRenderKitService(context, ExtendedRenderKitService.class);
    String script = "window.open('" + servletPath + "', '', 'location=0, status=0, resizable=1, scrollbars=0');";
    erks.addScript(FacesContext.getCurrentInstance(), script);
} catch (Exception e) {
    throw new FacesException("Redirection failed");
}

Wednesday, 19 February 2014

Get selected rows of ADF Table

Assuming you expose a binding (called 'resultTable') of the table component in a managed bean:
For multiple row selection (assuming a RichTable reference called myDataTable, based on a collection of MyObject objects):

// get the selected rows from a table component  
public void getMultipleRows(ActionEvent actionEvent) {
     RichTable table = getMyDataTable();
       for (Object facesRowKey : table.getSelectedRowKeys()) {
            table.setRowKey(facesRowKey);
            Object o = table.getRowData();
            MyObject selectedItem = (MyObject)o;
            if (selectedItem != null) {
                 // process the item
       }
   }
}
For single selection:
public Object getSelectedRow(RichTable table) {
   Object _selectedRowData = table.getSelectedRowData();
   JUCtrlHierNodeBinding _nodeBinding = (JUCtrlHierNodeBinding)_selectedRowData;
   return _nodeBinding.getRow();
}

So we can define a Selection Listener for the table, and this way we can get the source table component from the event itself:
// to get the selected Rows 
public void itemSelected(SelectionEvent selectionEvent) {
     RichTable table = (RichTable)selectionEvent.getSource();
     DCDataRow dcrow = (DCDataRow)getSelectedRow(table);
     MyObject selectedItem = (MyObject)dcrow.getDataProvider();
     // TODO ...
}

If the table is backed by a View Object, we can cast the selected row to a ViewRowImpl object:
public void itemSelected(SelectionEvent selectionEvent) {
     RichTable table = (RichTable)selectionEvent.getSource();
     ViewRowImpl row = (ViewRowImpl)getSelectedRow(table);
     if (row != null) {
        String attr1 = (String)row.getAttribute("attr1");
        String attr2 = (String)row.getAttribute("attr2");
        // ...
   }
}   

Check OID connection programmatically

This snippet of code allow us to check whether the connection to an OID Identity store is available.

import oracle.security.jps.JpsContext;
import oracle.security.jps.JpsContextFactory;
import oracle.security.jps.JpsException;
import oracle.security.jps.service.idstore.IdentityStoreService;

/**
  * Method to check that I can connect to OID Server. If I can get a
  * valid Identity Store means that there is a valid connection.
  */
private boolean oidUpAndRunning() {
    logger.info("Checking that OID is up and running...");
    try {
 getStoreService().getIdmStore();
 return true;
    } catch (JpsException e) {
 e.printStackTrace();
 return false;
    }
}

/**
 * Get an Identity Store Service from the JPS Context.
 */
public IdentityStoreService getStoreService() throws JpsException {
    JpsContextFactory ctxf = JpsContextFactory.getContextFactory();
    JpsContext ctx = ctxf.getContext();
    return ctx.getServiceInstance(IdentityStoreService.class);
}

Getting data from ADF bindings programmatically

These are some useful code snippets to work with ADF bindings programmatically:

// get the binding container  
BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();  
  
// get an ADF attributevalue from the ADF page definitions  
AttributeBinding attr = (AttributeBinding)bindings.getControlBinding("test");  
attr.setInputValue("test");  
  
// get an Action or MethodAction  
OperationBinding method = bindings.getOperationBinding("methodAction");  
method.execute();  
List errors = method.getErrors();  
  
method = bindings.getOperationBinding("methodAction");  
Map paramsMap = method.getParamsMap();  
paramsMap.put("param","value")  ;        
method.execute();  


// Get the data from an ADF tree or table  
DCBindingContainer dcBindings = 
        (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();  
  
FacesCtrlHierBinding treeData = (FacesCtrlHierBinding)bc.getControlBinding("tree");  
Row[] rows = treeData.getAllRowsInRange();  
  
// Get a attribute value of the current row of iterator  
DCIteratorBinding iterBind= (DCIteratorBinding)dcBindings.get("testIterator");  
String attribute = (String)iterBind.getCurrentRow().getAttribute("field1");  
  
// Get the error  
String error = iterBind.getError().getMessage();  

// refresh the iterator  
bindings.refreshControl();  
iterBind.executeQuery();  
iterBind.refresh(DCIteratorBinding.RANGESIZE_UNLIMITED);  
  
// Get all the rows of a iterator  
Row[] rows = iterBind.getAllRowsInRange();  
TestData dataRow = null;  
for (Row row : rows) {  
  dataRow = (TestData)((DCDataRow)row).getDataProvider();  
}  

// Get the current row of a iterator , a different way  
FacesContext ctx = FacesContext.getCurrentInstance();  
ExpressionFactory ef = ctx.getApplication().getExpressionFactory();  
ValueExpression ve = ef.createValueExpression(ctx.getELContext(), 
                "#{bindings.testIter.currentRow.dataProvider}", TestHead.class);  
TestHead test = (TestHead)ve.getValue(ctx.getELContext());  

 
// get the selected rows from a table component  
RowKeySet selection = resultTable.getSelectedRowKeys();  
Object[] keys = selection.toArray();  
List receivers = new ArrayList(keys.length);  
for ( Object key : keys ) {  
  User user = modelFriends.get((Integer)key);  
}  
  
// get  selected Rows of a table 2  
for (Object facesRowKey : table.getSelectedRowKeys()) {  
 table.setRowKey(facesRowKey);  
 Object o = table.getRowData();  
 JUCtrlHierNodeBinding rowData = (JUCtrlHierNodeBinding)o;  
 Row row = rowData.getRow();  
 Test testRow = (Test)((DCDataRow)row).getDataProvider() ;  
}  

Useful code snippets for ADF Security

Here are some useful code snippets related to ADF Security (thanks to Edwin Biemond blog):

// print the roles of the current user  
for ( String role : ADFContext.getCurrent().getSecurityContext().getUserRoles() ) {  
   System.out.println("role "+role);  
}  
  
// get the ADF security context and test if the user has the role users         
SecurityContext sec = ADFContext.getCurrent().getSecurityContext();  
if ( sec.isUserInRole("users") ) {  
}  

// is the user valid  
public boolean isAuthenticated() {  
 return ADFContext.getCurrent().getSecurityContext().isAuthenticated();  
}
  
// return the user  
public String getCurrentUser() {  
 return ADFContext.getCurrent().getSecurityContext().getUserName();  
}  

Friday, 14 February 2014

Showing popup in ADF during long running operations


An ADF application can trigger long running operations (DB queries, WS calls, etc), and this could cause user experience issues: user getting impatient, clicking everywhere and (possibly) crashing the application causing unpredictable behaviour (double submitting forms, modifying input data while running).

The following one is a solution proposed from Frank Nimphius in this article of ADF Code Corner: for every long running operation, we show an ADF popup (it's our choice if we want to make it modal or not), making a JS function call via the clientListener component.

The solution is based on 3 steps:

1) Create the popup component, making sure that contentDelivery is set to immediate (to render it when the page loads) and clientComponent is set to true (to make it accessible from JS):

<af:popup id="waitPopup" contentDelivery="immediate" clientComponent="true">
  <af:dialog id="waitDialog" type="none"
             title="#{resBundle.WAIT_POPUP_TITLE}" closeIconVisible="false">
    <af:panelGroupLayout id="pgl2" layout="vertical" halign="center">
     <af:image source="/images/scan.gif" id="i1"/>
     <af:outputText value="#{resBundle.WAIT_POPUP_MSG}" id="waitText"/>
    </af:panelGroupLayout>
  </af:dialog>
</af:popup>

2) Create JS code to disable the user input and open the popup; create a file named waitingpopup.js in a subfolder of public_html folder in your application, and write the following code inside it:
function enforcePreventUserInput(evt) {
    var popup = AdfPage.PAGE.findComponentByAbsoluteId('waitPopup');
    if (popup != null) {
        AdfPage.PAGE.addBusyStateListener(popup, handleBusyState);
        evt.preventUserInput();
    }
}

function handleBusyState(evt) {
    var popup = AdfPage.PAGE.findComponentByAbsoluteId('waitPopup');
    if (popup != null) {
        if (evt.isBusy()) {
            popup.show();
        }
        else if(popup.isPopupVisible()) {
            popup.hide();
            AdfPage.PAGE.removeBusyStateListener(popup, handleBusyState);
        }
    }
} 

After the file is saved, put the resource tag in the page/fragment containing the popup, using the correct path of the file created above (in this case the file has been created under public_html/scripts folder):
<af:resource type="javascript" source="/scripts/waitingpopup.js"/>

3) Trigger the popup by invoking the JS code above via clientListener:

<af:commandLink id="commandLink4" styleClass="btn btn-alt"
    disabled="#{isTaskRunning}"
    actionListener="#{bindings.longOperation.execute}"
    action="back"> 
  <af:clientListener method="enforcePreventUserInput" type="action"/> 
</af:commandLink>


What is not optimal in this solution is the part in which the JS retrieves the popup component by ID: this approach works smoothly if the popup is defined at top level (inside a JSF page or a JSF template: if the popup is defined inside a fragment, the ID for this component at runtime will be prefixed by the id of the region (something like 'r0:waitingPopup'), and in case the ADF taskflow containing this fragment is shown (for example) in a Portal page that is using a template, the component id is prefixed with the ID of the template as well; bottom line is, define this popup always at top level, or the code above won't always work.

Saturday, 5 November 2011

How to call JavaScript from a ADF Managed Bean

To run a JS function from our Managed Bean, first put the JS code in a <af:resource> component in our JSF page:
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1" 
           xmlns:f="http://java.sun.com/jsf/core" 
           xmlns:pe="http://xmlns.oracle.com/adf/pageeditor" 
           xmlns:cust="http://xmlns.oracle.com/adf/faces/customizable" 
           xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<af:resource type="javascript">
    function myFunc() { [ any JS code ] };
</af:resource>

In the managed bean, put the following code in the appropriate method (e.g. in a action listener if we want to execute the JS code after a commandButton or commandLink is selected):
import javax.faces.context.FacesContext;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
[…]
FacesContext facesContext = FacesContext.getCurrentInstance(); 
ExtendedRenderKitService service = (ExtendedRenderKitService) org.apache.myfaces.trinidad.util.Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
service.addScript(facesContext, "myFunc();");

Accessing an ADF Operation binding programmatically

Developing an ADF application, it sometimes comes out we need to invoke programmatically (e.g. from a Managed Bean) a method exposed as operation binding in a ADF Data Control. To do this, we need to access the current binding container:

OperationBinding searchOp = ADFUtils.findOperation("searchBusinessUnits");
The ADFUtils.findOperation() method has the following definition:
public static OperationBinding findOperation(String operationName) {
OperationBinding op = getDCBindingContainer().getOperationBinding(operationName);
if (op == null) {
throw new RuntimeException("Operation '" + operationName +"' not found");
}
return op;
}

Unfortunately, when the previous code is executed in a method action invoked at page load time through an invokeAction binding, it happens that the reference to the binding container is null at this point. In this case, we need to access the binding container in a different way, using EL:

import oracle.adfinternal.view.faces.model.binding.FacesCtrlActionBinding;

[. . .]

FacesCtrlActionBinding searchOp = null;
searchOp = (FacesCtrlActionBinding)JSFUtils.resolveExpression("#{data.portal_peoplefinder_resultsPageDef.searchBusinessUnits}");
Map opParams = searchOp.getParamsMap();
opParams.put("searchTerm", searchString);
Object result = searchOp.execute();

The pageDef excerpt of the page (or page fragment) containing the binding I need to access (in this case peopleFinder_resultsPageDef.xml ):

<bindings>
[...]
<methodAction id="searchBusinessUnits" InstanceName="ContentServicesDC.dataProvider"
DataControl="ContentServicesDC" RequiresUpdateModel="true"
Action="invokeMethod" MethodName="searchBusinessUnits" IsViewObjectMethod="false"
ReturnName="data.ContentServicesDC.methodResults.searchBusinessUnits_ContentServicesDC_dataProvider_searchBusinessUnits_result"/>
[...]
</bindings>

And the line of DataBindings.cpx regarding this binding:

<page id="portal_peoplefinder_resultsPageDef"
path="oracle.webcenter.portalapp.pagefragments.peoplefinder_resultsPageDef"/>

IMPORTANT: the EL expression we are using to retrieve the binding must be comply with the following format:

[“data”] + [id of the corresponding <page> entry in DataBindings.cpx] + [name of the binding we want to retrieve]