Posts

ADF Listeners - Part III

ADF Application Event Listeners, QueryString Parameters reinjection between sessions – Part III

In ADF applications as any web application you can make use of QueryString parameters to perform custom actions inside of your application. But what happens to your QueryString parameters when the current session expires? In ADF they are lost between sessions. So, how can we reinject the QueryStrings parameters in the new session? You have two options:

  • You can manually call again the application with the same QueryString parameters. But what if you’re using your application inside of another? Probably this option may not work.
  • You can try to catch the session timeout. But you need to catch the session timeout before it actually expires otherwise you lost the QueryString parameters. How to do it?

The answer to the previous question resides on the ADF application Events Listeners. In my previous posts you can find details about ADF application Events Listeners. Take a look here.

In this post I will show you how to accomplish this task.

 

Solution

In order to gather the current session QueryString parameters and reinject them in the newest one before session timeout occur you need to create the following custom listeners:

  • Custom Phase Listener
  • Custom Filter

Inside of the custom phase listener class we will be listening the lifecycle phases of our application, gather the QueryString parameters and save them in a cookie so we are able to access them in the future when the session timeout happens. The following code explains how to do it.

package view.listeners.session;

import java.util.Map;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class CustomPhaseListener implements PhaseListener{
    public CustomPhaseListener() {
        super();
    }

    public void afterPhase(PhaseEvent phaseEvent) {
        System.out.println("CustomPhaseListener");
    }

    public void beforePhase(PhaseEvent phaseEvent) {
        System.out.println("CustomPhaseListener");
        FacesContext vFacesContext = phaseEvent.getFacesContext();
        ExternalContext vExternalContext = vFacesContext.getExternalContext();
        HttpSession session = (HttpSession) vExternalContext.getSession(false);
        boolean newSession = (session == null) || (session.isNew());
        boolean postback = !vExternalContext.getRequestParameterMap().isEmpty();
        boolean timedout = postback && newSession;
        
        if (!timedout)
        {
            //Returns all QueryString paramters but you are only interested in 
            //yours parameters.
            Map<String, Object[]> queryStringMap = ((HttpServletRequest)vExternalContext.getRequest()).getParameterMap();
            
            //This utility class detectes which QueryString parameters are 
            //generated  by the ADF or have been created by you.
            QueryStringUtils qsConstants = new QueryStringUtils();
            //Returns a string with all QueryString parameters created by you.
            String queryString = qsConstants.getStringQueryStringParameters(queryStringMap);
            
            if (queryString != null && !queryString.isEmpty() &&
                !vExternalContext.getRequestCookieMap().containsKey(CookieConstants.COOKIE_QUERY_STRING_NAME))
            {
                //Inserts the QueryString parameters in a COOKIE.
                HttpServletResponse vResponse = (HttpServletResponse)vExternalContext.getResponse();
                Cookie cookie = new Cookie(CookieConstants.COOKIE_QUERY_STRING_NAME, queryString);
                vResponse.addCookie(cookie);
            }
        }
    }

    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }
}

You can find the code for the QueryStringUtils here:

package view.listeners.session;

import java.net.URLDecoder;
import java.net.URLEncoder;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class QueryStringUtils {
    
    //Example of QueryString parameters that the application accepts.
    public static final String QUERY_STRING_1 = "_qs1";
    public static final String QUERY_STRING_2 = "_qs2";
    
    private List listOfQueryStringConstants;

    public QueryStringUtils(){
        listOfQueryStringConstants = new ArrayList();
        listOfQueryStringConstants.add(QUERY_STRING_1);
        listOfQueryStringConstants.add(QUERY_STRING_2);
    }
    
    public List getQueryStringConstantsNames() {
        return listOfQueryStringConstants;
    }
    
    public Hashtable getHashQueryStringParameters(Map<String, Object[]> queryStringParams) {
        Hashtable result = new Hashtable();
        
        for(Entry<String, Object[]> entry : queryStringParams.entrySet()) {
              if (getQueryStringConstantsNames().contains(entry.getKey())) 
              {
                  Object propertyValue = entry.getValue()[0];
                  if (propertyValue != null)
                  {
                      try
                      {
                          String propertyValueAux = URLDecoder.decode(propertyValue.toString(), "UTF-8");
                          result.put(entry.getKey(), propertyValueAux);
                      }
                      catch(Exception ex) {
                          ex.printStackTrace();
                      }
                  }    
              }
        }
        
        return result;
    }

    public String getStringQueryStringParameters(Map<String, Object[]> queryStringParams) {
        String result = "";
        int i = 0;
        
        for(Entry<String, Object[]> entry : queryStringParams.entrySet()) {
              if (getQueryStringConstantsNames().contains(entry.getKey())) 
              {
                  Object propertyValue = entry.getValue()[0];
                  if (propertyValue != null)
                  {
                      try
                      {
                          String propertyValueAux = URLEncoder.encode(propertyValue.toString(), "UTF-8");
                          if (i == 0)
                            result += entry.getKey() + "=" + propertyValueAux;
                          else
                            result += "&" + entry.getKey() + "=" + propertyValueAux;
                          i ++;
                      }
                      catch(Exception ex) {
                          ex.printStackTrace();
                      }
                  }    
              }
        }
        
        return result;
    }
}

In the class CookieConstants you have:

package view.listeners.session;

public class CookieConstants {
    
    public static final String COOKIE_QUERY_STRING_NAME = "QUERY_STRING_COOKIE_EXAMPLE";
}

In the custom filter we will create a custom ServletRequest so we can insert the QueryString parameters for each new request. When the session timeout happens the custom filter is invoked and the QueryString parameters saved in the cookie are read and inserted in the request of the newest session created. Here is the code for the custom filter:

package view.listeners.session;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;


public class CustomFilter implements Filter{
    
    private FilterConfig _filterConfig = null;
    
    public void init(FilterConfig filterConfig) {
        _filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse,
                         FilterChain filterChain) throws java.io.IOException, 
                                                         javax.servlet.ServletException{
        CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest)servletRequest);
        filterChain.doFilter(requestWrapper, servletResponse);
    }

    public void destroy() {
        _filterConfig = null;
    }
}

In the custom ServletRequest we will manipulate the request data and reinject the QueryString parameters. The code for the custom ServletRequest is presented next:

package view.listeners.session;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper{
    
    private Hashtable<String,String> queryStringParameters;
    
    public CustomHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        setHashQueryStringParameters();
    }

    private String getCookieQueryStringParameters() {
        String result = null;
        Cookie[] cookie = super.getCookies();
        
        for(int i = 0; i < cookie.length; i++) {
            if (cookie[i].getName().equalsIgnoreCase(CookieConstants.COOKIE_QUERY_STRING_NAME)) {
                result = cookie[i].getValue();
            }
        }
        
        return result;
    }

    private void setHashQueryStringParameters() {
        queryStringParameters = new Hashtable<String, String>();
        String parameters = getCookieQueryStringParameters();
        
        if (parameters != null && !parameters.isEmpty()) 
        {
            String[] splitParameters = parameters.split("&");
            
            for (int j = 0; j < splitParameters.length; j++)
            {
                String[] keyValue = splitParameters[j].split("=");
                queryStringParameters.put(keyValue[0], keyValue[1]);
            }
        }
    }

    public ArrayList getQueryStringParametersNames() {
        return new ArrayList<String>(queryStringParameters.keySet());
    }

    @Override
    public Map getParameterMap() {
        return super.getParameterMap();
    }

    @Override
    public Enumeration getParameterNames() {
        Enumeration enumeration = super.getParameterNames();
        
        if(queryStringParameters.size() != 0){
            //Custom Enumeration to set the default ADF QueryString parameters 
            //and our custom parameters.
            CustomEnumeration myEnumeration = new CustomEnumeration(enumeration, getQueryStringParametersNames());
            enumeration = myEnumeration.getEnumeration();
        }
        return enumeration;
    }

    @Override
    public String[] getParameterValues(String string) {
        String[] result = super.getParameterValues(string);
        
        if (queryStringParameters.size() != 0 && queryStringParameters.containsKey(string)){
            result = new String[1];
            result[0] = queryStringParameters.get(string);
        }
        
        return result;
    }

    @Override
    public String getParameter(String string) {
        String result = super.getParameter(string);
        
        if (queryStringParameters.containsKey(string))
            result = queryStringParameters.get(string);
        
        return result;
    }
}

The code for the CustomEnumeration class can be found here:

package view.listeners.session;

import java.util.ArrayList;
import java.util.Enumeration;

import weblogic.utils.enumerations.IteratorEnumerator;

public class CustomEnumeration {
    private Enumeration enumeration;
    private ArrayList<String> queryStringParametersNames;
    
    public CustomEnumeration(Enumeration enumeration, ArrayList<String> queryStringParametersNames) {
        this.enumeration = enumeration;
        this.queryStringParametersNames = queryStringParametersNames;
    }
    
    public Enumeration getEnumeration() {
        ArrayList<String> arrayList = new ArrayList<String>(); 
        while (enumeration.hasMoreElements()) {
            arrayList.add((String)enumeration.nextElement());
        }
        
        arrayList = addqueryStringParameters(arrayList);
        
        Enumeration result = new IteratorEnumerator(arrayList.iterator()); 
        return result;
    }
    
    private ArrayList<String> addqueryStringParameters(ArrayList<String> arrayList) {
        
        for (int i = 0; i < queryStringParametersNames.size(); i++) {
            String value = queryStringParametersNames.get(i);
            if (!arrayList.contains(value))
                arrayList.add(value);
        }
        return arrayList;
    }
}

Conlusion

By intercepting the application lifecycle phases and the page requests using a custom phase listener and a custom filter we have been able to reinject QueryString parameters between sessions.

 

Cheers,

Pedro Gabriel

 

@PedrohnGabriel

Post original image by Fe Ilya

ADF Listeners - Part II

ADF Application Event Listeners – Part II

Hi all,

In my previous post  ADF Application Event Listeners – Part I I have focused in some of the ADF applications event listeners that we can listen and how to do it. In this post I will show you some examples of data that you can get from those event listeners and in some cases rewrite it.

 

HTTP Session Events

After application session is created the sessionCreated method is triggered. From the HttpSessionEvent input parameter in the same method you are able to access data from these classes:

  • servlet.http.HttpSession
  • servlet.internal.session.MemorySessionData
  • servlet.internal.session.MemorySessionContext
  • servlet.internal.WebAppServletContext

For internal classes is not recommend to make any change on them, however, you are able to access it for your own purpose.

In order to get these previous classes you just need the following:

public void sessionCreated(HttpSessionEvent httpSessionEvent) {
   HttpSession httpSession = httpSessionEvent.getSession();   

   MemorySessionData msd = (MemorySessionData)httpSessionEvent.getSource();
                
   MemorySessionContext msc = (MemorySessionContext)msd.getContext();

   WebAppServletContext appServletContext = msd.getWebAppServletContext();
}

 

In the next table is presented the resume of what you may find.

Class Method Description
HttpSession getId() Returns de the unique identifier assigned to the created session.
getCreationDate() Returns the time when the session was created measured in milliseconds.
getMaxInactiveInterval() Returns the maximum time interval, in seconds that the servlet container will keep the session open between client accesses. If configured the value will be the same as configured in the property “Session Timeout” in the “web.xml” file.
getLastAccessedTime() Returns the last time the client sent a request associated with this session measured in milliseconds.
Invalidate() Invalidated this session then unbinds any objects bound to it.
MemorySessionData getConcurrentRequestCount() Returns the number of concurrent requests for the application.
MemorySessionContext getCurrOpenSessionsCount() Returns the number of concurrent open sessions for the application.
getPersistentStoreType() The scope type where the session data is stored. This value will be the same as configured in the property “Store Type” in the “weblogic-application.xml”.
getTotalOpenSessionsCount() Returns the number open sessions for the application.
getWebAppServletContext() Returns the class that retrieves the context of the current servlet of the application. We will see in further detail this class.

Servlet Context Listener

The Servlet Context is initiated during the first application access after deployment. For future accesses to the application the servlet context is reused interchangeably of the new sessions created.

After the servlet context is initialized the contextInitialized method is triggered. From the ServletContextEvent input parameter in the same method you are able to access data from these classes:

  • servlet.internal.WebAppServletContext
  • application.internal.ApplicationContextImpl
  • management.configuration.AppDeploymentMBean
  • servlet.internal.WebAppConfigManager
  • management.configuration.WebAppComponentMBeanImpl
  • management.runtime.ServletRuntimeMBean

For internal classes is not recommend to make any change on them, however, you are able to access it for your own purpose.

In order to get these previous classes you just need the following:

public void contextInitialized(ServletContextEvent servletContextEvent) {
   WebAppServletContext wasc = (WebAppServletContext)servletContextEvent.getSource();
        
   ApplicationContextImpl acimpl = (ApplicationContextImpl)wasc.getApplicationContext();
   
   AppDeploymentMBean appDeploymentMBean = acimpl.getAppDeploymentMBean();
        
   WebAppComponentMBeanImpl appComponentMBean = WebAppComponentMBeanImpl)wasc.getMBean();
        
   ServletRuntimeMBean[] srmb = wasc.getServletRuntimeMBeans();
}

 

In the next table is presented the resume of what you may find.

Class Method Description
WebAppServletContext getAppDisplayName() Application display name.
getMBean() Returns the WebAppComponentMBeanImpl class.
getServletRuntimeMBeans() Returns the ServletRuntimeMBean class.
getClasspath() Returns the path for all jars included in the application.
getDocroot() Returns the path for the WAR file of the application.
getMajorVersion() Returns the major version of the application.
getMinorVersion() Returns the minor version of the application.
getApplicationSecurityRealmName() Returns the security realm name of the user logged in.
getApplicationParameters() Application Configuration Parameters. This is further detailed next.
getAbsoluteSourcePath() The path of the application’s installation.
getServer() Returns the name of the server where the application is deployed in.
getServerInfo() Returns the server info where the application is deployed in. We will provide an example next.
ApplicationContextImpl getAuthRealmName() Returns the realm name of the user logged in.
getDefaultEncoding() Returns application’s default encoding.
getDispatchPolicy() The class of work executed in queues of the weblogic.
getMimeTypeDefault() Returns application’s mime type.
AppDeploymentMBean getSessionCookieName() Returns the internal name of the session’s cookie.
WebAppConfigManager getSessionJDBCConnectionTimeoutSecs() Returns in seconds the JDBC connection timeout.
getSessionPersistentStoreDir() In my tests I have found “session_db” value.
getSessionPersistentStoreTable() In my tests I have found “wl_servlet_sessions” value.
WebAppComponentMBeanImpl getSessionPersistentStoreType() In my tests I have found “memory” value.
getSessionTimeoutSecs() Returns in seconds the session time out.
ServletRuntimeMBean getName() Returns the name of the servlet.
getType() Returns the type of the servlet.

 

In the getServerInfo() method from the WebAppServletContext class you can find something like this:

“WebLogic Server 10.3.5.0 Fri Apr 1 20:20:06 PDT 2011 1398638 Oracle WebLogic Server Module Dependencies 10.3 Thu Mar 3 14:37:52 PST 2011 Oracle WebLogic Server on JRockit Virtual Edition Module Dependencies 10.3 Thu Feb 3 16:30:47 EST 2011”

 

In the getApplicationParameters() method from the ApplicationContextImpl class you can find for example the following parameters:

Parameter Definition
“weblogic.app.rmiGracePeriod” The amount of time, in seconds, that the work manager accepts and schedules RMI calls until there are no more RMI requests arriving within the RMI grace period during a gracefulshutdown or a retirement.
“weblogic.app.ignoreSessions” Immediately places the application into Administration mode without waiting for current HTTP sessions to complete.
“weblogic.app.adminMode” Indicates that a running application should switch to Administration mode and accept only Administration requests via a configured Administration channel. If this option is not specified, the running application is stopped and cannot accept Administration or client requests until is it restarted.

 

In the ServletRuntimeMBean class you can find for example the following servlets:

Name Type
BIGRAPHSERVLET ServletRuntime
JspServlet ServletRuntime
Faces Servlet ServletRuntime
FileServlet ServletRuntime
resources ServletRuntime
adw ServletRuntime
WebServiceServlet ServletRuntime
MapProxyServlet ServletRuntime
BIGAUGESERVLET ServletRuntime
GatewayServlet ServletRuntime

Servlet Request Listener

The Servlet Request Listener is triggered whenever a new request is made to the server regarding the current application. For those cases the requestInitialized method is triggered with the ServletRequestEvent class as input parameter.

ServletRequestEvent and ServletContextEvent extend from the same java class “java.util.EventObject”. You will be able to find the same data as detailed for the “Servlet Context Listener”.

Phase Listeners

You can listen to all lifecycle phases. From the beforePhase and afterPhase methods you are able to access and manipulate data from these classes:

  • servlet.http.HttpServletRequest
  • servlet.http.HttpServletResponse

You can get these classes as detailed next:

public void beforePhase(PhaseEvent phaseEvent) {
   //You get the current phase for what the event has been triggered.        
   System.out.println("getPhaseId: " + phaseEvent.getPhaseId());
        
   FacesContext vFacesContext = phaseEvent.getFacesContext();    
   ExternalContext vExternalContext = vFacesContext.getExternalContext();
        
   HttpServletRequest vRequest = (HttpServletRequest)vExternalContext.getRequest());
        
   Map<String, Object[]> queryStringMap = vRequest.getParameterMap();
        
   HttpServletResponse vResponse = (HttpServletResponse)vExternalContext.getResponse();
}

 

Note: Don’t forget to set the getPhaseId method to trigger all or only the phases that you really want when you are creating your own custom Phase Listener.

public PhaseId getPhaseId() {
  return PhaseId.ANY_PHASE;
}

 

If you create a custom Filter you are able to manipulate the data from the request and response by setting the data from the servletRequest and servletResponse input parameters’ classes for the doFilter method.

In order to set the data from the servletRequest class do the following steps:

  1. Create a class that extends from “servlet.http.HttpServletRequestWrapper” class.CustomHttpServletRequestWrapper
  2. Override the methods you want to customize.CustomHttpServletRequestWrapper_OverideMethods
  3. Set the new class in the doFilter method.
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse,
                         FilterChain filterChain) throws java.io.IOException, javax.servlet.ServletException{
            
       CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest)servletRequest);
            
       filterChain.doFilter(requestWrapper, servletResponse);
    }
    
    

 

On the next post we’ll explore how to use these application events to get custom query string parameters and reinject them in new sessions after session’s time out.

Cheers,

Pedro Gabriel

 

@PedrohnGabriel

Feature Image by Melvin Gaal

ADF Listener - Header

ADF Application Event listeners – Part I

Hi all and welcome to a new series on Red Mavericks!

This one is technical, focused on Oracle Application Development Framework, or ADF, so… sorry to our Business Analyst readers. There’s a new article coming out to new next week about Advanced Web Form creation… stay tuned.

Anyway, today’s article is written by a new Maverick: Pedro Gabriel. Welcome Pedro!

Pedro is a senior ADF developer at Link Consulting, and he’ll be sharing some of his experience with our fellow techie readers. He would be very interested in hearing back from you through twitter @PedrohnGabriel. Be sure to follow him  and check his Bio, right here🙂

So, without further ado, here is Pedro’s article.


ADF applications provide a wide range of Event Listeners triggered whenever a change in state occurs. With these event listeners you are able to interact with:

  • The state of the servlet context
  • The state of the servlet request
  • The HTTP session object
  • Servlet Filters
  • Phase Listeners

 

Servlet Context Events / Servlet Request Events

This type of events involves resources or state held at the level of the application servlet context/request object. You have four types of servlet context events:

 

Event Type Interface Methods Description
Servlet Context Listener javax.servlet.ServletContextListener contextInitialized() Servlet context is created.
contextDestroyed() Servlet context is about to be destroyed.
Servlet Context Attributes Listener javax.servlet.ServletContextAttribuestListener attributeAdded() An attribute is added to the Servlet Context Listener.
attributeRemoved() An attribute is removed from the Servlet Attribute Listener.
attributeReplaced() An attribute is replaced from the Servlet Context Listener.
Servlet Request Listener javax.servlet.ServletRequestListener requestInitialized() The request is about to come into scope of the web application.
requestDestroyed() The request is about to go out of scope of the web application.
Servlet Request Attributes listener javax.servlet.ServletRequestAttribuestListener attributeAdded() A new attribute was added to the servlet request. Called after the attribute is added.
attributeRemoved() A new attribute was removed from the servlet request. Called after the attribute is removed.
attributeReplaced() A new attribute was replaced from the servlet request. Called after the attribute is replaced.

 

From the moment the ADF application is invoked until it is totally rendered for usage by the end user the events are triggered in the following order:

ServletEventsOrder

In order to listen and interact to any of these event listeners you need to create a new servlet context or request listener class and implement the previous mentioned interfaces. The next image shows how to create it.

CustomServletContext

Then you need to register them in the “web.xml” file in order to listen and interact to the events for the servlet context or request listeners. Set the custom event listener class path. For now on when you run the ADF application the filter will be triggered.

CustomServletContext_Web_xml

HTTP Session Events

This type of events involves resources or state associated with series of requests from a single user session that is associated with the HTTP session object. You have two types of http session events:

 

Event Type Interface Methods Description
HTTP Session Listener javax.servlet.http.HttpSessionListener sessionCreated() An HTTP session is activated.
sessionDestroyed() An HTTP session is about to be passivated.
HTTP Session Attribute Listener vavax.servlet.http.HttpSessionAttributeListener attributeAdded() An attribute is added to the HTTP session listener.
attributeRemoved() An attribute is removed from the HTTP session listener.
attributeReplaced() An attribute is replaced from the HTTP session Listener.

 

The HTTP session events are executed in the following order:

HttpEventsOrder

To listen and interact to any of these event listeners you need to create a new HTTP listener class and implement the previous mentioned interfaces. The next image shows how to create it.

HttpSessionListener

Then you need to register them in the “web.xml” file in order to listen and interact to the events for the HTTP event listeners. Set the custom event listener class path. For now on when you run the ADF application the filter will be triggered.

HttpSessionListener_WebXml

Servlet Filters

Servlet filters are used for pre-processing Web application requests and post-processing responses. Sometimes modifying the response from a class of servlets during pre-processing might be useful. You can have as much filters as you want and are invoked based on the order they are configured in the web.xml file.

When you create a new filter class it must implement the “javax.servlet.Filter” interface. The next image shows how to create it.

CustomFilter

You will find your custom filter implementing 3 methods:

  • init – filter initialization and saves the filter configuration in a variable.
  • doFilter – filter implementation. You can check whether the filter is called during a request or a response.
  • destroy – filter finalization. You can override this method to perform extra actions.

After filter creation you must register it on the “web.xml” file in order to listen and interact to the events for the filter.

CustomFilter_Register

Phase Listeners

ADF lifecycle integrates with JSF request lifecycle. By using a phase listener, you can listen to the events fired before and after for any of the ADF lifecycle phases, and execute custom code. Take a look at the JSF and ADF lifecycles in the next image so you can understand the range of events you can listen:

adf_jsf_lifecycle

In order to listen and interact to ADF lifecycle phases you need to create a new phase listener class and implement the “javax.faces.event.PhaseListener” interface. The next image shows how to create it.

CustomPhaseListener

Then you need to register it in the “faces-config.xml” file in order to listen and interact to the events. Set the custom phase event listener class path.

CustomPhaseListener_FacesConfig

Conclusion

By creating your own event listeners classes you are able to listen and interact with a wide range and variety of data that is triggered whenever you perform any action in your ADF application.

On the next post we’ll provide some examples regarding the type of data that you can find and intercept in the event listeners.

Cheers,

Pedro Gabriel

 

@PedrohnGabriel