Friday, February 14, 2014

Logging DML statements

For a while now, I've been wondering is it possible to know the generated DML statements and their parameter values; since this might be helpful sometimes. And finally I have managed to do this, I will list the steps below.

steps:
1) generate a java class for the targeted entities or use a base entity class.
2) override the buildDMLStatement method and your custom logic, similar to:
protected StringBuffer buildDMLStatement(int i , AttributeDefImpl[] attributeDefImpl ,
                                             AttributeDefImpl[] attributeDefImpl2 ,
                                             AttributeDefImpl[] attributeDefImpl3 , boolean b) {
        StringBuffer buffer =
            super.buildDMLStatement(i , attributeDefImpl , attributeDefImpl2 , attributeDefImpl3 , b) ;
        logger.info("created dml statement  (for object:" + getEntityDef().getName() + getKey() + "):" +
                    buffer.toString()) ;

        return buffer ;
    }

3)override the bindDMLStatement method and add your custom logic, similar to:
protected int bindDMLStatement(int i , PreparedStatement preparedStatement , AttributeDefImpl[] attributeDefImpl ,
                                   AttributeDefImpl[] attributeDefImpl2 , AttributeDefImpl[] attributeDefImpl3 ,
                                   HashMap hashMap , boolean b) throws SQLException {
        String[] attrs = getAttributeNames() ;
        for (String attrName : attrs) {
            if (isAttributeChanged(getAttributeIndexOf(attrName))) {
                logger.info("attribute[" + attrName + "] changed, " + "postedValue:" +
                            getAttribute(getAttributeIndexOf(attrName) , ORIGINAL_VERSION) + ", newValue:" +
                            getAttribute(attrName)) ;
            }
        }
        return super.bindDMLStatement(i , preparedStatement , attributeDefImpl , attributeDefImpl2 ,
                                      attributeDefImpl3 , hashMap , b) ;
    }


You are done now. using the above code- in the base entity class- will log all generated DML statements.

Full class looks like:
package com.ahmad.model ;

import java.sql.PreparedStatement ;
import java.sql.SQLException ;

import java.util.HashMap ;

import java.util.logging.Logger ;

import oracle.jbo.server.AttributeDefImpl ;
import oracle.jbo.server.EntityImpl ;



public class BaseEntity extends EntityImpl {
    public BaseEntity() {
        super() ;
    }
    Logger logger = Logger.getLogger(BaseEntity.class.getName()) ;

    protected int bindDMLStatement(int i , PreparedStatement preparedStatement , AttributeDefImpl[] attributeDefImpl ,
                                   AttributeDefImpl[] attributeDefImpl2 , AttributeDefImpl[] attributeDefImpl3 ,
                                   HashMap hashMap , boolean b) throws SQLException {
        String[] attrs = getAttributeNames() ;
        for (String attrName : attrs) {
            if (isAttributeChanged(getAttributeIndexOf(attrName))) {
                logger.info("attribute[" + attrName + "] changed, " + "postedValue:" +
                            getAttribute(getAttributeIndexOf(attrName) , ORIGINAL_VERSION) + ", newValue:" +
                            getAttribute(attrName)) ;
            }
        }
        return super.bindDMLStatement(i , preparedStatement , attributeDefImpl , attributeDefImpl2 ,
                                      attributeDefImpl3 , hashMap , b) ;
    }

    protected StringBuffer buildDMLStatement(int i , AttributeDefImpl[] attributeDefImpl ,
                                             AttributeDefImpl[] attributeDefImpl2 ,
                                             AttributeDefImpl[] attributeDefImpl3 , boolean b) {
        StringBuffer buffer =
            super.buildDMLStatement(i , attributeDefImpl , attributeDefImpl2 , attributeDefImpl3 , b) ;
        logger.info("created dml statement  (for object:" + getEntityDef().getName() + getKey() + "):" +
                    buffer.toString()) ;

        return buffer ;
    }

    protected boolean isAttributeChanged(int i) { //it seems this method is used to determine if the attribute is chnaged or not, so that it will be included in the generated dml
        return super.isAttributeChanged(i) ;
    }

}



Update on: 17 February,2014:
found out that you can achieve a similar result by using your own class that extends DBTransactionImpl2 class and overriding the createPreparedStatement method to log the passed string. But if you want to have more control about which Entities' DMLs you want to log, then use the first approach.

No comments:

Post a Comment