Monday, February 13, 2017

Bit #40 - adfAuthentication servlet allow_logout_url_param parameter

I was googling all over for some documentation on the allow_logout_url_param_overwrite initialization parameter of the adfAuthentication servlet in web.xml and guess what... (yes, you guessed right) I could not find anything on it. After digging into it, disassembling the library code and all, it turns out that this parameter is used in the following ADF code snippet in oracle.adf.share.security.authentication.AuthenticationServlet (the adfAuthentication servlet in web.xml):

      if (session != null) {
         endUrl = (String)session.getAttribute(paramEndUrl);
         session.removeAttribute(
paramEndUrl);  
      }

      if ((overwriteLogoutUrl ||
endUrl == null) && parameters.containsKey(paramEndUrl)) {
         String[]
paramEndUrlVals = (String[]) parameters.get(paramEndUrl);
        
endUrl = paramEndUrlVals[0];
      }


As you can see from the above code, the allow_logout_url_param_overwrite parameter when set to "true" allows you to overwrite the logout URL (if one is specified during logout) with the one defined with the end_url parameter in web.xml.

Another interesting tip is that when a logout URL is not specified during logout (endUrl == null above), the one defined by the end_url parameter in web.xml (if one is defined) is used no matter what the value of the allow_logout_url_param_overwrite parameter is. Makes sense.

That's all!

Thursday, December 6, 2012

Oracle JDeveloper 11gR2 Cookbook

After almost a year of truly great effort by everyone involved, I am happy to announce that my Oracle JDeveloper 11gR2 Cookbook book is published by Packt Publishing. This book accumulates to a large degree my practical experience amassed over the last four years working on real world ADF projects.

Special Thanks goes to Frank Nimphius, Edwin Biemond and Spyros Doulgeridis for their insight, knowledge and advice.

For further details about the book click here

Here are some peer references/reviews of the book from the blog sphere:

Monday, February 27, 2012

Bit #39 - Retrieving the current session id at the ADFBC layer

If you need to retrieve the current session identifier at the ADF Business Components layer, use the getId() method defined in the oracle.jbo.SessionContext interface. You can get the oracle.jbo.SessionContext interface by calling getCurrentSession() which is defined in the oracle.jbo.SessionContextManager interface. So, how do you get the oracle.jbo.SessionContextManager interface? Call any of the findOrCreateSessionContextManager() or getSessionContextManager() static methods in SessionImpl. Finally, you may asking why you might need the current session id at the ADFBC layer? In my case, I had to log it in the database as part of a generic session audit process during DML. Here is an example:

Example:

// in the context of ADFBC
SessionImpl.findOrCreateSessionContextManager().getCurrentSession().getId()

Notes:
Note #1: The oracle.jbo.SessionContext interface also provides a method called getType() that returns the session type. It can be any of the following: TYPE_HTTP_SESSION, TYPE_EJB_SESSION or TYPE_THREAD_SESSION.

Note #2: Here are some example session ids retrieved when calling oracle.jbo.SessionContext.getId():
  • HTTP session (original session): FGHpPKhfwJSQ5hkKChGnNyhCH10sVrvyGGL44GSz1vCpyZQbkFJX!2144650654!1330307487797_wsc30xy1y_1
  • HTTP session (same session, another browser tab): FGHpPKhfwJSQ5hkKChGnNyhCH10sVrvyGGL44GSz1vCpyZQbkFJX!2144650654!1330307487797_wsc30xy1y_5
  • ADF Model Tester: d7a748c1-0343-4f50-91d6-171cf9f8c5e5__root_frame_
  • ADF Model Tester (after File | Reload application): d7a748c1-0343-4f50-91d6-171cf9f8c5e5__root_frame_
Context:

ADF Business Components 

Wednesday, January 11, 2012

Bit #38 - Creating a custom ADF Faces client-side converter

You can create a custom ADF Faces client-side converter by ensuring that your converter class implements the org.apache.myfaces.trinidad.convert.ClientConverter interface. This is done in addition to implementing the javax.faces.convert.Converter interface, which implements the custom converter on the server. To implement the ClientConverter interface you need to provide implementation for the getClientConversion() and getClientScript() methods. The getClientConversion() implementation should return the JavaScript constructor of the client converter. The getClientScript() implementation on the other hand should return the actual JavaScript code that implements the client converter.

Example:

public class CustomConverter implements javax.faces.convert.Converter,
                             org.apache.myfaces.trinidad.convert.ClientConverter {
 
    // implement the javax.faces.convert.Converter interface for server-side conversion
  
    // implement the org.apache.myfaces.trinidad.convert.ClientConverter interface for
    // client-side conversion

    // return the JavaScript client converter
    public String getClientConversion(FacesContext context, UIComponent component) {
        return "new CustomConverter()";
    }

    // return the actual client converter JavaScript code
    public String getClientScript(FacesContext context, UIComponent component) {
        return null;
    }
}

For a complete implementation of an ADF Faces client converter take a look at this reference from an older Oracle documentation: http://docs.oracle.com/cd/B25221_05/web.1013/e18745/devguide/clientValidation.html#Client-side%20Validators. Unfortunately, this example is not part of the latest documentation.

Context:

ADF Faces

Sunday, January 8, 2012

Bit #37 - Preventing client events from propagating to the server

ADF Faces client events, i.e. events delivered and implemented on the browser using JavaScript,  by default do propagate to the server. There might be cases however that you don't want this default propagation. For instance, consider an af:commandButton component that defines a clientListener but has no actionListener defined. In this case propagating the client event to the server would be unnecessary. To stop the client event from propagating to the server use the cancel() method of the event class. Event classes are subclasses of the AdfBaseEvent class.

You listen to client events by using the af:clientListener component to call a JavaScript method in response to a client event. The af:clientListener component is used as a child of the ADF Faces component that generates the event.

Finally, note that in order to be able to cancel an event from propagating to the server, the event must be cancelable. You can determine whether an event is cancelable or not by calling the event isCancelable() method. This method returns true if event propagation can be canceled.

Example:

function customClientListener(event)
{

    // cancel event propagation to the server
    if (
event.isCancelable()) {
        event.cancel();
    }

    // do client event processing
}


Context:

ADF Faces

Saturday, January 7, 2012

Bit #36 - Preventing client UI input during server event processing

To prevent any client UI input during the server processing of an event use the AdfCustomEvent preventUserInput() method in your JavaScript client listener. Calling this method prior to queuing the event will display a glass pane covering the browser window and will prevent further user input until the server event processing is complete. To use this method in a client listener first construct an AdfCustomEvent and and then call preventUserInput() on it before calling queue() to propagate the event to the server. Add custom client and server listeners using the af:clientListener and af:serverListener ADF Faces components as children of the component generating the client event.

To make this a generic implementation, think about providing your own custom queue() JavaScript method that accepts among others a boolean indicator called preventInput to indicate whether client UI input is to be prevented or not during the server event processing. For instance: queue(source,serverListener,params,immediate,ppr,preventInput).

Here is an example client listener demonstrating how to use preventUserInput():

Example:

function customClientListener(event)
{

    // get the event source
    var source = event.getSource();

  
    // create the event
    var customEvent = new AdfCustomEvent
(source, "customServerListener", {}, true);
    // call preventUserInput() to block UI input
    customEvent.preventUserInput();

    // send the event to the server
    customEvent.queue(true);
}


Context:

ADF Faces

Friday, January 6, 2012

Bit #35 - Using client behavior tags with ADF Faces

Partial page rendering (PPR) is supported in ADF Faces through the use of the partialTrigers attribute and the AdfFacesContext addPartialTarget() method (see Bit #10 - Selectively enabling Partial Page Rendering programmatically). PPR however can also be achieved in ADF Faces applications using the JSF 2.0 client behavior API and the use of client behavior tags such as the f:ajax tag. This tag is added as a child tag to an ADF Faces component and allow for the execution of PPR in response to a component client event. The specifications of the f:ajax tag is shown below:

<f:ajax event="..." render="..." execute="..." listener="..." ...

event is a string indicating on which events an Ajax request will be fired,
render is a string indicating the identifiers of the components to render
execute is a string indicating the identifiers of the components to be processed on the server
listener indicates a method to invoke during the Ajax request

Complete documentation on the f:ajax tag can be found here: http://javaserverfaces.java.net/nonav/docs/2.0/pdldocs/facelets/f/ajax.html.

Here is an example of how to use the f:ajax tag to achieve PPR of an af:outputText based on a value change event originating from an af:inputText component:

Example:

<af:inputText ...
    <f:ajax name="change" render="ot" execute="@this" />
</af:inputText>
<af:outputText id="ot" ...


The @this value for the execute attribute indicates that only the component that triggered the Ajax request will be processed on the server.

Context:

ADF Faces

Monday, January 2, 2012

Bit #34 - Using JavaScript partitioning

JavaScript partitioning is the way ADF Faces partitions and delivers JavaScript code to the client. ADF Faces groups its ADF Faces components JavaScript code into so called features and then packages and delivers related features in so called JavaScript partitions. There are two files involved in the delivery of JavaScript partitions to the client: adf-js-features.xml and adf-js-partitions.xml. The first lists the JavaScript classes that make up a feature and its relationships with other features. The second groups the JavaScript features in partitions.

Of course JavaScript can also be delivered to the client by directly adding the JavaScript code to the page or referencing a JavaScript library in the page. Bundling all of your JavaScript code in a few JavaScript Libraries will result in longer download time, while adding JavaScript directly to each page will result in more roundtrips to the server. This is why partitioning is used, as an alternative to specifically tune and customize the JavaScript requirements on a per-application basis.

Here are some examples of the adf-js-features.xml and adf-js-partitions.xml JavaScript partitioning files:

Example:

META-INF/adf-js-features.xml

<?xml version="1.0" encoding="utf-8" ?>
<adf-js-features xmlns="http://xmlns.oracle.com/adf/faces/feature">
  <features xmlns="http://xmlns.oracle.com/adf/faces/feature">
    <feature>
      <feature-name>CustomComponent</feature-name>
      <feature-class>js/custom/CustomComponent.js</feature-class>
      <feature-class>js/custom/CustomComponentEvent.js</feature-class>
      <feature-dependency>AdfRichPopup</feature-dependency>
    </feature>

  </features>
</adf-js-features> 


WEB-INF/adf-js-partitions.xml

<?xml version="1.0" encoding="utf-8" ?>
  <partitions xmlns="http://xmlns.oracle.com/adf/faces/partition">
     <partition>
       <partition-name>CustomPartition</partition-name>
       <feature>CustomComponent</feature>
       <feature>CustomCommon</feature>
       <feature>CustomUtils</feature>
     </partition>

    </partitions>

Context:

ADF Faces

Friday, December 30, 2011

Bit #33 - Using custom client attributes

To use a custom client attribute for an ADF Faces component use an af:clientAttribute component as a child component of that component and specify the name and value of the custom attribute. Then use the JavaScript AdfUIComponent.getProperty() method to retrieve the property value at runtime on the client.

Note that custom client attributes are not delivered to the server automatically. To do so you must create a custom event from the client to the server using an af:serverListener component and queue the event by calling AdfCustomEvent.queue().

Here is an example of adding a custom client attribute to an af:inputText component. We have added an af:clientListener to demonstrate calling the AdfUIComponent.getProperty() method.

Example:

            <af:inputText label="Label 1" id="it1">
                <af:clientAttribute name="customAttribute" value="Hello, world"/>
                <af:clientListener type="valueChange" method="onInputTextValueChange"/>
            </af:inputText>


....
            <af:resource type="javascript">
            function onInputTextValueChange(event) {
                var inputText = event.getSource();
                // retrieve and display the custom client attribute
                alert(inputText.getProperty("customAttribute"));
            }
            </af:resource>



Context:

ADF Faces

Wednesday, December 28, 2011

Bit #32 - Locating a component on the client

To locate a component on the client side of an ADF Faces application use any of the AdfUIComponent.findComponent() or AdfPage.PAGE.findComponentByAbsoluteId() methods. Both of these methods accept the component's identifier. The difference between the two is that while AdfUIComponent.findComponent() accepts a relative expression representing the component identifier, AdfPage.PAGE.findComponentByAbsoluteId() expects an absolute expression for the component's identifier. Absolute expressions use a fully qualified client identifier with a leading separator character, for example :container1:container2:componentId.

To guaranty that a client side instance of the component exists, ensure that you have set the component's clientComponent property to true. Alternatively, you can add a clientListener to the component instead.

Finally, do not use the AdfPage.PAGE.findComponent() method because its implementation may change from release to release.

Example:

function exampleFunc(actionEvent) { 
    var someComponent=actionEvent.getSource();
    // use findComponent() to locate a component relative to 'someComponent'
    var someOtherComponent=someComponent.findComponent("componentId");
    someOtherComponent.setValue("Hello") 


Context:

ADF Faces

Monday, July 4, 2011

Bit #31 - Making an Entity object read-only

There are a few different ways to make an Entity object read-only, both declaratively in JDeveloper or programmatically via the ADF Business Components API. One that is suggested in OTN thread http://forums.oracle.com/forums/thread.jspa?threadID=2247578&tstart=0 is to change in the Entity's General section the Entity's Updatable property from true (the default) to false. This property can be found under the Type section in the Property Inspector.


By changing it to false, the Entity will not be updatable for all Entity-based View objects that use it. Note however that JDeveloper will still show the Entity reference as being Updatable in the View object Entity Objects page. This seems to be a bug in JDeveloper.

Some of the other ways to make the Entity read only would be to uncheck the Updatable checkbox for each View object that uses the Entity object (in the Entity Objects section), to use the isAttributeUpdatable() API to return false for all attributes or even at the attribute level to set each attribute's Updatable property to Never.

Context:
Entity Objects

Friday, May 6, 2011

Bit #30 - Displaying the current row on an af:table

You can display the current record number as you navigate an af:table by using certain information available on the table's iterator binding, namely the currentRowIndexInRange and rangeStart attributes. The current row can be calculated by the following EL expression: #{bindings.Iterator.rangeStart+bindings.Iterator.currentRowIndexInRange+1}, where Iterator is the table's bound iterator identifier. We add one because the row index is 0-based. You will need to surround the af:table with an af:panelCollection and use one of its facets - I suggest using the secondaryToolbar facet - to add an af:toolbar with an af:outputText inside it. For the current record count to be updated as you navigate the table, you will need to setup a partialTrigger on the af:outputText to the af:table. The example below shows this implementation.

Example:

<af:panelcollection ... >
<af:table id="tbl1" ... >
  </af:table>

    <f:facet name="secondaryToolbar">
      <af:toolbar id="t1">
        <af:group id="g1">
          <af:outputtext id="ot24" value="#{bindings.Employees1Iterator.rangeStart+bindings.Employees1Iterator.currentRowIndexInRange+1}/#{bindings.Employees1Iterator.estimatedRowCount} records">
                                         visible="#{bindings.Employees1Iterator.currentRow ne null}"
                                         partialTriggers="tbl1 ::qryId1"/>
        </af:group
>
      </af:toolbar>
    </f:facet>
  </af:panelcollection>

Here is what the output looks like:


Context:

JSF page

Thursday, March 24, 2011

Bit #29 - Dynamically configure ADF trace logs in WebLogic

ADF-specific logging can be dynamically configured in WebLogic via the wlst script. Ensure that you run the wlst script that is located in oracle common directory (and not the one in the WebLogic server home). Then connect to the administration server and use the setLogLevel() command to change the appropriate logger's level. To configure Business Components logs specify oracle.jbo as the logger. Similarly to configure the ADF Controller and ADF Faces logs use the oracle.adf.controller and oracle.adf.faces loggers respectively. For the example below, the ADF application is deployed on ManagedServer1. As mentioned, these changes to the logging configuration can be done at run-time without the need to re-start the server.


Example:

wlst
connect('weblogic','weblogic1', 't3://192.168.5.134:7001')
setLogLevel(target='ManagedServer1', logger='oracle.jbo', level='FINEST')


Context:

ADF BC
ADF Faces
ADF Controller


References:

http://jdeveloperfaq.blogspot.com/2011/03/faq-33-how-to-configure-adf-diagnostics.html

Tuesday, December 14, 2010

Bit #28 - Using findDefObject() to load a BC definition object from its metadata XML

If you ever thought of parsing any of the ADF Business Components (BC) metadata XML files for the sake of extracting various metadata information, you might want to think twice. The ADF framework offers higher level APIs to do this routine job. Case in point: take a look at the findDefObject() methods available in a number of definition classes such as oracle.jbo.server.EntityDefImpl and oracle.jbo.server.ViewDefImpl for example. By calling this method, the metadata is parsed and loaded for you into the corresponding EntityDefImpl or ViewDefImpl. Neat! Then extracting metadata information is as easy as calling the corresponding methods. For example, to get all the attributes defined for a View Object, you can call ViewDefImpl.getAttributeDefs(). When calling findDefObject() ensure that the location of your BC definition files is listed in the class path. Here is an example:

Example:

import oracle.jbo.AttributeDef;
import oracle.jbo.server.AttributeDefImpl;
import oracle.jbo.server.EntityDefImpl;
import oracle.jbo.server.ViewDefImpl;


public class ADFMetaDataTester {

    public static void main(String[] args) {

      // load EO definition from Employee.xml
      EntityDefImpl eoDef = EntityDefImpl.findDefObject("Employee");
      // now, you can for example get the unique keys defined by the EO
      AttributeDefImpl[] uniqueKeys = eoDef.getUniqueKeys();

      // load VO definition from EmployeesVO.xml
      ViewDefImpl  voDef = ViewDefImpl.findDefObject("EmployeesVO");
      // get the VO attributes
      AttributeDef[] attributes = voDef.getAttributeDefs();
    }
}


Context:

ADF Business Components (BC)

Wednesday, November 24, 2010

Bit #27 - Setting a View Object attribute's Queryable property

Expanding on Bit #26 - Overriding getAttributeDef() to conditionally set an attribute property, you can set a View Object's attribute queryable property simply by calling setQueriable() on its ViewAttributeDefImpl. As explained in Bit #26, you can get the AttributeDef attribute definition by calling getAttributeDef() and passing the attribute index as a parameter. In order to call any of the attribute set...() methods, you will have to cast the AttributeDef interface to an ViewAttributeDefImpl implementation. By the way, did you know that by setting an attribute's queryable property will show or hide a View Criteria Item (i.e. the criterion) based on the attribute on the af:query dialog? Another way to hide the criterion was outlined in Bit #25 - Hiding a View Criteria item based on some condition. It will also show or hide the attribute from the Add Fields drop-down in the Advanced mode of af:query. One last thing: check-out the plethora of set...() methods available in the ViewAttributeDefImpl. As you may have guessed it, pretty much everything that is available declaratively on the Edit Attribute dialog, can be set (or reset) dynamically in your code based on some business condition. For a complete use case, check out the reference listed below.

Example:

  /**
   * Helper to set an attribute's queriable property.
   * Example:
   *    setQueriable(ViewRowImpl.SOMEFIELDINDEX, something.equals(somethingElse));
   *
   * @param attribIndex the attribute index
   * @param condition the condition (true/false)
   */
  protected void setQueriable(int attribIndex, boolean condition) {
      // set the attribute queryable as needed
      AttributeDef def = super.getAttributeDef(attribIndex);
      boolean queryable = condition;

      // set/reset queriable only if needed
      if (def != null && def.isQueriable() != queryable) {
          ViewAttributeDefImpl attributeDef = (ViewAttributeDefImpl)def;
          attributeDef.setQueriable(queryable);
      }
  }


Context:

View Object Implementation Class

References:

http://dstas.blogspot.com/2010/03/set-queryable-property-on-attribute.html
Related Posts Plugin for WordPress, Blogger...