Wednesday, October 9, 2013

List All Dirty Entities in the current transaction

I was asked once if it was possible to list all dirty entities in the transaction regardless of the entity type.
After some thinking and reading, I reached the solution I am about to describe:

1)override the default DBTransactionImpl2 as described in:Extending ADF framework base classes
2)override the getTransactionPostListenersList and make it public.

the mentioned function returns a list that contain classes that implements the TransactionPostListener interface, such as :ViewObjectImpl,EntityImpl.

you can test the object by using the following code :
  transactionPostListener instanceof EntityImpl
to see if it's an Entity.

please note that if you find a ViewObject in the list that it does not necessarily have a dirty row.
simply iterating the rows of the ViewObject will add it to the list.

some other functions that may be of value are:
--addTransactionStateListener; by testing the method, found that this is the method used to add the ViewObject to the list returned by :getTransactionPostListenersList.
--addTransactionPostListenerNoCheck: by testing the method, found that this is the method used to add the Entity to the list returned by :getTransactionPostListenersList.
-- removeTransactionPostListener: by testing the method, found that this is the method used to remove the Post Listener from the list returned by :getTransactionPostListenersList.

Tuesday, October 8, 2013

Session TimeOut

First of all, I would like to point out that this article has more to do with J2EE than ADF.

In some projects you may face a requirement that the application should have a session timeout set to a certain value that is persisted somewhere and a user of the system with admin privileges should be able to set this value through one of the screens.

Of course, you can simply set the session timeout in the web.xml of the application. but this method will be static and if you want to modify the session timeout you will have to modify the web.xml then restart the application.

If you want the session timeout to be set dynamically then you can use the following code:
    int timeInSeconds=2;//add your custom logic here to retrieve the timeout value
    ((HttpSession)FacesContext.getCurrentInstance().getExternalContext().
     getSession(false)).setMaxInactiveInterval(timeInSeconds);

add the above code, so that it will always be called for all the users after the login. either use Phase listener or sessionListener.

ADF: Customizing the History columns

 ADF developer will often be faced with a requirement that dictates that each some table in the database should have some audit info ( who created the record and when, who made the last changes and when).
Luckily, ADF comes with out-of-the-box support for these requirements, all you have to do is set the desired column as a history column of the desired type in the entity and the framework will take care of filling the values. There are some default types that are already defined.

Okay, so far so good. But what if you have to append something to the username or if you have to use the given name of the user(that you can get by implementing your own code to map the user name to the given name),how can you override the framework behavior?
you can acheive this by overriding the EntityImpl class with your own Class.
as for how to override the EntityImpl class check: Extending ADF Framework Base Classes.

now in your Custom EntityImpl Class, add the following code:
    protected Object getHistoryContextForAttribute(AttributeDefImpl attributeDefImpl){
        if(attributeDefImpl.getHistoryKind()==AttributeDefImpl.HISTORY_CREATE_USER){
            //add your Custom logic here
        }else{
            return super.getHistoryContextForAttribute(attributeDefImpl);
        }
    }

doing so will let you set the value of the history column with your own value.


Extending ADF framework base classes

If you have been reading on the ADF framework best practices, you will often read that it's recommended to extend some of the base classes of the framework; so that you can inject your code as required later on in the application development cycle without having to make a huge amount of changes.

in this article I will talk about how to do that.
first, let's start with the tough one: DBTransactionImpl2.
you can override the DBTransactionImpl2 with your custom class by doing the following:
           1)create a new java class that extends the DBTransactionImpl2 class. let's name
                 it MyCustomTransactions.
           2) create a new java class that extends the DatabaseTransactionFactory. let's name 
                it MyCustomTransactionFactory.
           3) in the MyCustomTransactionFactory add the following code:
                        public DBTransactionImpl2 create(){
                       //        return super.create();
                         return new MyCustomTransactions();
                       }
               as you can see from the above code we return an instance of 
               our MyCustomTransactions class.
           4)go to the application module, open the Configuration tab and 
              edit the desired configuration.
           5)in the Edit Business Components Configuration popup that appeared,
               go to the Properties tab. 
           6)change the value of the TransactionFactory property to the fully qualified name of 
                the MyCustomTransactions class, i.e.: <package name>.ClassName

with this the framework will now use our custom class instead of the default one. So, when you call the getTransaction() method from the application module, you will get an instance of the custom class.

now that we are done with overriding the DBTransactionImpl2 class, I will explain how to override the other classes.
this can be achieved simply  by:
           1) writing classes that extend the following: 
                oracle.jbo.server.EntityCache
                oracle.jbo.server.EntityImpl
                oracle.jbo.server.EntityDefImpl
                oracle.jbo.server.ViewObjectImpl
                oracle.jbo.server.ViewRowImpl 
                oracle.jbo.server.ViewDefImpl
                oracle.jbo.server.ApplicationModuleImpl
                oracle.jbo.server.ApplicationModuleDefImpl
           2)open the project properties of the model project.
           3)from the tree to left of the Project Properties popup 
                 expand the Business Components node,
                 then  expand  the Base Classes sub-node .
           4) now direct the JDeveloper to your base classes.
this is it. 
Of course, you don't have to override all the base classes if you feel that it's not necessary.

I will write about some uses in future articles.