com.p5solutions.core.jpa.orm.EntityPersisterImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.p5solutions.core.jpa.orm.EntityPersisterImpl.java

Source

/* Pivotal 5 Solutions Inc. - Core Java library for all other Pivotal Java Modules.
 * 
 * Copyright (C) 2011  KASRA RASAEE
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
package com.p5solutions.core.jpa.orm;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.persistence.Table;
import javax.sql.DataSource;

import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.p5solutions.core.jpa.orm.DMLOperation.OperationType;
import com.p5solutions.core.jpa.orm.annotations.FetchBeforeSave;
import com.p5solutions.core.jpa.orm.entity.aop.EntityProxy;
import com.p5solutions.core.jpa.orm.transaction.PersistenceContext;
import com.p5solutions.core.jpa.orm.transaction.PersistenceContext.EntityState;
import com.p5solutions.core.jpa.orm.transaction.PersistenceProvider;
import com.p5solutions.core.jpa.orm.transaction.TransactionTemplate;
import com.p5solutions.core.utils.ReflectionUtility;

/**
 * EntityPersisterImpl: Implementation of the {@link EntityPersister} interface. The implementation helps in executing
 * dml operations for a given entity type, generated by the {@link EntityPersistUtility}.
 * 
 * @author Kasra Rasaee
 * @since 2010-11-01
 * 
 * @see EntityPersistUtility generation of the basic dml operations used to persist data to the database
 * @see EntityParser for information on how to parse query results to a single-list of entities.
 * @see TransactionTemplate interface defining the rules for the transaction template implementation.
 * @see EntityDetail a class holding access methods and related data on a given entity or table-entity type.
 * @see ParameterBinder binding data for a single property within a given entity or table-entity
 * @see NamedParameterJdbcTemplate a name based paramaterization jdbc template by spring.
 * @see MapUtility and its implementation {@link MapUtilityImpl} maps a value to a given path within a object instance.
 * @see InterceptorUtility intercepting of entities before and after they have been saved / updated / merged / deleted.
 */
public class EntityPersisterImpl implements EntityPersister {

    /** The logger. */
    private static Log logger = LogFactory.getLog(EntityPersisterImpl.class);

    /** The conversion utility. */
    private ConversionUtility conversionUtility;

    /** The entity parser. */
    private EntityParser entityParser;

    /** The map utility. */
    private MapUtility mapUtility;

    /** The entity utility. */
    private EntityUtility entityUtility;

    /** The data source. */
    private DataSource dataSource;

    /** The jdbc template. */
    private NamedParameterJdbcTemplate jdbcTemplate;

    /** The interceptor utility. */
    private InterceptorUtility interceptorUtility;

    /**
     * The transaction template. a hook back into the transaction template; possible use, get next sequence value?
     */
    private TransactionTemplate transactionTemplate;

    /**
     * Global fetch-before-save property that will affect saving any/all entities.
     */
    private Boolean fetchBeforeSave;

    /**
     * Instantiates a new entity persister.
     */
    public EntityPersisterImpl() {
        super();
    }

    /**
     * Checks if is oracle data source.
     * 
     * @return true, if is oracle data source
     * @see com.p5solutions.core.jpa.orm.EntityPersister#isOracleDataSource()
     */
    @Override
    public boolean isOracleDataSource() {
        // TODO check for other types, possible abstract out
        return true;
    }

    /*
     * USING THE RETURNING CLAUSE IN A DML OPERATION COULD BE A "NICE TO HAVE"
     *//*
         * public boolean appendReturningClause(ParameterBinderExtended binder, StringBuilder returningColumns,
         * StringBuilder returningBinders) {
         * 
         * if (Comparison.isNotEmpty(binder.getSequenceName())) { if (returningColumns.length() > 0) { // add a comman ,
         * returningColumns.append(getSQLParameterSeparaterCharacter());
         * returningBinders.append(getSQLParameterSeparaterCharacter()); }
         * 
         * returningColumns.append(binder.getColumnName()); if (isNamedParameterJdbcTemplate()) { // Use param name since
         * we are using the // NamedParameterJdbcTemplate, template! returningBinders.append(getBindingCharacter());
         * returningBinders.append(binder.getBindingName()); } else { //use index instead. ?? only if we use JdbcTemplate!
         * returningBinders.append("?"); } return true; }
         * 
         * return false; }
         * 
         * public void appendAll(ParameterBinderExtended binder, StringBuilder fields, StringBuilder values, StringBuilder
         * returningColumns, StringBuilder returningBinders) {
         * 
         * appendField(binder, fields); appendValue(binder, values); //appendReturningClause(binder, returningColumns,
         * returningBinders); }
         */

    /**
     * Checks if is named parameter jdbc template.
     * 
     * @return true, if is named parameter jdbc template
     * @see com.p5solutions.core.jpa.orm.EntityPersister#isNamedParameterJdbcTemplate()
     */
    @Override
    public boolean isNamedParameterJdbcTemplate() {
        // if its a standard jdbc template and not some named parameterized
        // template
        return getJdbcTemplate() instanceof NamedParameterJdbcTemplate;
    }

    /**
     * Gets the join column value.
     * 
     * @param entity
     *          the entity
     * @param pb
     *          the pb
     * @return the join column value
     */
    protected Object getJoinColumnValue(Object entity, ParameterBinder pb) {
        Object value = null;

        if (pb.isOneToOne()) {
            // throw not implemented yet.
            throw new RuntimeException(
                    new NotImplementedException(pb.getEntityClass() + " - " + pb.getColumnNameAnyJoinOrColumn()));
        } else if (pb.isOneToMany()) {
            // TODO ignore, this is not a column, inverse join on the ManyToOne side
        } else if (pb.isManyToMany()) {

            String msg = "Many-to-many not supported plese check entity type " + pb.getEntityClass()
                    + " and join column " + pb.getColumnNameAnyJoinOrColumn();
            logger.error(msg);

            // throw not implemented yet.
            throw new RuntimeException(new NotImplementedException(msg));
        } else if (pb.isManyToOne()) {
            // find value from the primary key.
            DependencyJoin dj = pb.getDependencyJoin();

            // TODO check ?? at this point, DependencyJoin should never be null.
            // TODO probably build in a generic entity class dump / import such that
            // we can do testing on framework??
            ParameterBinder joinPB = dj.getDependencyParameterBinder();

            // temporarily store the join parameter such that we can get the parameter
            // binder value from it.
            Object temp = mapUtility.get(pb, entity, pb.getBindingPath());

            // now get the value from the target join object, using its dependency
            // join
            // TODO does not support join columns! NOT YET..
            value = mapUtility.get(joinPB, temp, joinPB.getBindingPath());
        }
        return value;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.p5solutions.core.jpa.orm.EntityPersister#executeDML(java.lang.String, java.util.Map)
     */
    @Override
    public Long executeDML(String sql, Map<String, Object> params) {
        MapSqlParameterSource paramSource = new MapSqlParameterSource(params);
        // TODO <Object> should be of type T? how? import
        // org.apache.poi.hssf.record.formula.functions.T;??
        Integer updated = getJdbcTemplate().execute(sql, paramSource,
                new PersistPreparedStatementCallback<Integer>());
        return updated != null ? updated.longValue() : 0L;
        //return 0L;
    }

    /**
     * Process.
     * 
     * @param entityClass
     *          the entity class
     * @param entity
     *          the entity
     * @return the map sql parameter source
     * @see com.p5solutions.core.jpa.orm.EntityPersister#process(java.lang.Class, java.lang.Object)
     */
    @Override
    public MapSqlParameterSource process(Class<?> entityClass, Object entity) {

        // TODO needs serious cleaning up... some sort of state-machine type
        // processing.

        MapSqlParameterSource paramSource = new MapSqlParameterSource();
        EntityDetail<?> entityDetail = getEntityUtility().getEntityDetail(entityClass);
        List<ParameterBinder> pbs = entityDetail.getParameterBinders();

        boolean isDebug = logger.isDebugEnabled();
        logger.debug("** Mapping values from entity -> " + entity.getClass() + " to DML parameter source.");

        for (ParameterBinder pb : pbs) {
            Object value = null;
            String bindingPath = pb.getBindingPath();
            String bindingPathSQL = pb.getBindingPathSQL();
            String debugMessage = "     ";

            if (pb.isPrimaryKey()) {
                if (isDebug) {
                    debugMessage += "[* Id] ";
                }
                // TODO probably a good idea to implement @EmbeddedId
                // TODO probably a good idea to implement @IdClass

                // let the below code handle the value retrieval.
                // value = mapUtility.get(pb, entity, bindingPath);
            }

            if (pb.isColumn()) {
                value = mapUtility.get(pb, entity, bindingPath);
            } else if (pb.isEmbedded()) {
                value = mapUtility.get(pb, entity, bindingPath);
            } else if (pb.isJoinColumn()) {
                value = getJoinColumnValue(entity, pb);
            }

            if (isDebug) {
                debugMessage = "Binding parameter [" + pb.toString() + "]";
            }

            // check if the value is a generated value
            if (pb.isGeneratedValue() && value == null) {
                String sequenceName = pb.getSequenceName();
                value = getTransactionTemplate().getSequenceValue(sequenceName);

                // Map the sequence value to the entity's parameter
                mapUtility.map(pb, entity, value, bindingPath);

                if (isDebug) {
                    debugMessage += " <Generated> using sequence name " + sequenceName;
                }
            }

            if (isDebug) {
                if (value != null) {
                    debugMessage += " with value of " + value;
                } else {
                    debugMessage += " with value of <DBNull>";
                }

                logger.debug(debugMessage);
            }

            // use the binding path as the binding name of the sql paramater
            // source since embedded, or join objects can be multi-level depths.
            paramSource.addValue(bindingPathSQL, value);
        }
        return paramSource;
    }

    /**
     * Gets the DML operation based on the table-entity class type and the operation type.
     * 
     * @param clazz
     *          the clazz
     * @param operationType
     *          the operation type
     * @return the dML operation
     */
    protected DMLOperation getDMLOperation(Class<?> clazz, OperationType operationType) {

        DMLOperation operation = getEntityUtility().getDMLOperation(clazz, operationType);

        if (operation == null) {
            String msg = "No " + operationType + " DML operation type found for table-entity of class type " + clazz
                    + " please make sure it is part of the " + TransactionTemplate.class
                    + " bean definition, and table is defined with the " + Table.class + " annotation!";
            logger.error(msg);
            throw new NullPointerException(msg);
        }

        return operation;
    }

    /**
     * Save, Update, or Delete an entity within the database, use the operation type to suggest what to do.
     * 
     * @param <T>
     *          the generic type
     * @param entity
     *          the entity
     * @param operationType
     *          the operation type
     * @return the t
     */
    @SuppressWarnings("unchecked")
    protected <T> T saveUpdateMergeOrDelete(T entity, OperationType operationType) {
        if (entity == null) {
            String msg = "** Cannot perform " + operationType
                    + " DML operation on a null entity!, good luck finding the source! Suggestion, "
                    + "use a conditional breakpoint 'entity == null' at the some call level step back to the root of the problem!";
            logger.error(msg);
            throw new NullPointerException(msg);
        }

        // extract the target object before persistence.
        entity = EntityUtility.getTargetEntity(entity);
        Class<?> clazz = EntityUtility.getTargetEntityClass(entity);

        DMLOperation operation = getDMLOperation(clazz, operationType);
        String sql = operation.getStatement();
        MapSqlParameterSource paramSource = process(clazz, entity);
        getJdbcTemplate().execute(sql, paramSource, new PersistPreparedStatementCallback<Integer>());

        return entity;
    }

    /**
     * Save or update.
     * 
     * @param <T>
     *          the generic type
     * @param entity
     *          the entity
     * @return the t
     * @throws Exception
     *           the exception
     * @see com.p5solutions.core.jpa.orm.EntityPersister#saveOrUpdate(T)
     */
    @Override
    public <T> T saveOrUpdate(T entity) throws Exception {
        if (entity == null) {
            String msg = "** Cannot perform INSERT or UPDATE DML operation on a null entity!, good luck finding the source! Suggestion, "
                    + "use a conditional breakpoint 'entity == null' at the some call level step back to the root of the problem!";
            logger.error(msg);
            throw new NullPointerException("Cannot save or update null entity");
        }

        @SuppressWarnings("unchecked")
        Class<T> entityClass = EntityUtility.getTargetEntityClass(entity);
        EntityDetail<T> entityDetail = getEntityUtility().getEntityDetail(entityClass);

        // get the persistence context for the given thread
        PersistenceContext context = PersistenceProvider.get();

        // if the entity is of entity proxy, then it must already be persisted
        // don't check the fetch-before-save, it has to be updated
        if (entity instanceof EntityProxy) {
            entity = update(entity);
        } else if (entityDetail.isPrimaryKeyNull(entity)) {
            // if the primary key of the entity is null, then it hasn't been persisted
            // don't check the fetch-before-save, it has to be inserted
            entity = save(entity);
        } else {
            // now, if the entity is neither a proxy and it has a valid primary key,
            // then we should check the persistence context for this transaction
            // to make sure that it already hasn't been persisted.
            String entityKey = entityDetail.getEntityKey(entity);

            // check the context
            if (context.exists(entityKey)) {
                // TODO throw error? perhaps a flag to determine if it should or not??
                entity = update(entity);
            } else {
                // check the fetch-before-save to see whether we're doing the save or
                // not
                if (isFetchBeforeSaveWarranted(entityClass)) {
                    // save it only if it is not already saved (not in context at this
                    // point)
                    if (getEntityParser().find(entity) == null) {
                        entity = save(entity);
                    } else {
                        entity = update(entity);
                    }
                } else {
                    // fetch before save is not required so save it anyway
                    entity = save(entity);
                }
            }
        }

        // add or update the entity state within the persistence context
        String entityKey = entityDetail.getEntityKey(entity);
        context.update(entityKey, entity, EntityState.SAVE);

        return entity;
    }

    /**
     * Verify if the fetch before save is to be done.
     * 
     * @param entityClass
     * @return
     */
    private boolean isFetchBeforeSaveWarranted(Class<?> entityClass) {
        return fetchBeforeSave || ReflectionUtility.hasAnyAnnotation(entityClass, FetchBeforeSave.class);
    }

    /**
     * Merge.
     * 
     * @param <T>
     *          the generic type
     * @param entity
     *          the entity
     * @return the t
     * @throws Exception
     *           the exception
     * @see com.p5solutions.core.jpa.orm.EntityPersister#merge(T)
     */
    @Override
    public <T> T merge(T entity) throws Exception {
        // TODO fix me
        throw new NotImplementedException("the merge does not yet work properly, as such it is not ready for use");
        // return saveUpdateMergeOrDelete(entity, OperationType.MERGE);
    }

    /**
     * Save.
     * 
     * @param <T>
     *          the generic type
     * @param entity
     *          the entity
     * @return the t
     * @throws Exception
     *           the exception
     * @see com.p5solutions.core.jpa.orm.EntityPersister#save(T)
     */
    @Override
    public <T> T save(T entity) throws Exception {
        entity = getInterceptorUtility().beforeSave(entity);
        entity = saveUpdateMergeOrDelete(entity, OperationType.INSERT);
        entity = getInterceptorUtility().afterSave(entity);
        return entity;
    }

    /**
     * Update.
     * 
     * @param <T>
     *          the generic type
     * @param entity
     *          the entity
     * @return the t
     * @throws Exception
     *           the exception
     * @see com.p5solutions.core.jpa.orm.EntityPersister#update(T)
     */
    @Override
    public <T> T update(T entity) throws Exception {
        entity = getInterceptorUtility().beforeUpdate(entity);
        entity = saveUpdateMergeOrDelete(entity, OperationType.UPDATE);
        entity = getInterceptorUtility().afterUpdate(entity);
        return entity;
    }

    /**
     * Delete.
     * 
     * @param <T>
     *          the generic type
     * @param entity
     *          the entity
     * @return the int
     * @throws Exception
     *           the exception
     * @see com.p5solutions.core.jpa.orm.EntityPersister#delete(T)
     */
    @Override
    public <T> int delete(T entity) throws Exception {
        getInterceptorUtility().afterDelete(entity);
        Object ret = saveUpdateMergeOrDelete(entity, OperationType.DELETE);
        getInterceptorUtility().afterDelete(entity);

        // return the number of rows affected
        return ret instanceof Integer ? ((Integer) ret).intValue() : 0;
    }

    /**
     * Delete.
     * 
     * @param <T>
     *          the generic type
     * @param tableClass
     *          the table class
     * @param id
     *          the id
     * @return the int
     * @throws Exception
     *           the exception
     * @see com.p5solutions.core.jpa.orm.EntityPersister#delete(java.lang.Class, java.lang.Object)
     */
    @Override
    public <T> int delete(Class<T> tableClass, Object id) throws Exception {
        // T t = saveUpdateOrDelete(entity, OperationType.DELETE);

        // TODO check for null on entity detail
        EntityDetail<T> entityDetail = getEntityUtility().getEntityDetail(tableClass);

        // get the dml operation
        DMLOperation operation = getEntityUtility().getDMLOperation(tableClass, OperationType.DELETE);
        MapSqlParameterSource paramSource = new MapSqlParameterSource();

        // build the parameter value list
        List<ParameterBinder> pkParameterBinders = entityDetail.getPrimaryKeyParameterBinders();
        if (pkParameterBinders == null) {
            String msg = "Primary key parameter binders cannot be null for given table-entity class type of "
                    + tableClass;
            logger.error(msg);
            throw new NullPointerException(msg);
        } else if (pkParameterBinders.size() != 1) {
            String msg = "There is a total of " + pkParameterBinders.size()
                    + " when there should only be one, when calling delete(clazz, id);";
            logger.error(msg);
            throw new RuntimeException(msg);
        }

        ParameterBinder pkpb = pkParameterBinders.get(0);
        paramSource.addValue(pkpb.getBindingName(), id);

        Integer updated = getJdbcTemplate().execute(operation.getStatement(), paramSource,
                new PersistPreparedStatementCallback<Integer>());

        return updated;
        // return the number of rows affected
        //return ret instanceof Integer ? ((Integer) ret).intValue() : 0;
    }

    /**
     * The Class PersistPreparedStatementCallback.
     * 
     * @param <T>
     *          the generic type
     */
    protected class PersistPreparedStatementCallback<T> implements PreparedStatementCallback<T> {

        /*
         * (non-Javadoc)
         * 
         * @see org.springframework.jdbc.core.PreparedStatementCallback#doInPreparedStatement (java.sql.PreparedStatement)
         */
        @SuppressWarnings("unchecked")
        @Override
        public T doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
            // TODO Auto-generated method stub

            if (ps.execute()) {
                ResultSet rs = ps.getResultSet();
                // TODO fix me...
                return null;
            } else {
                return (T) new Integer(ps.getUpdateCount());
            }
        }

    }

    /**
     * Gets the data source.
     * 
     * @return the data source
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getDataSource()
     */
    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * Sets the data source.
     * 
     * @param dataSource
     *          the new data source
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setDataSource(javax.sql.DataSource)
     */
    @Override
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * Gets the jdbc template.
     * 
     * @return the jdbc template
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getJdbcTemplate()
     */
    @Override
    public NamedParameterJdbcTemplate getJdbcTemplate() {
        if (jdbcTemplate == null) {
            jdbcTemplate = new NamedParameterJdbcTemplate(getDataSource());
        }
        return jdbcTemplate;
    }

    /**
     * Sets the jdbc template.
     * 
     * @param jdbcTemplate
     *          the new jdbc template
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setJdbcTemplate(org.springframework.jdbc
     *      .core.namedparam.NamedParameterJdbcTemplate)
     */
    @Override
    public void setJdbcTemplate(NamedParameterJdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * Sets the entity utility.
     * 
     * @param entityUtility
     *          the new entity utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setEntityUtility(com.p5solutions.core.jpa.orm. EntityUtility)
     */
    @Override
    public void setEntityUtility(EntityUtility entityUtility) {
        this.entityUtility = entityUtility;
    }

    /**
     * Gets the entity utility.
     * 
     * @return the entity utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getEntityUtility()
     */
    @Override
    public EntityUtility getEntityUtility() {
        return entityUtility;
    }

    /**
     * Sets the conversion utility.
     * 
     * @param conversionUtility
     *          the new conversion utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setConversionUtility(com.p5solutions.core.jpa.orm
     *      .ConversionUtility)
     */
    @Override
    public void setConversionUtility(ConversionUtility conversionUtility) {
        this.conversionUtility = conversionUtility;
    }

    /**
     * Gets the conversion utility.
     * 
     * @return the conversion utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getConversionUtility()
     */
    @Override
    public ConversionUtility getConversionUtility() {
        return conversionUtility;
    }

    @Override
    public EntityParser getEntityParser() {
        return entityParser;
    }

    @Override
    public void setEntityParser(EntityParser entityParser) {
        this.entityParser = entityParser;
    }

    /**
     * Gets the map utility.
     * 
     * @return the map utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getMapUtility()
     */
    @Override
    public MapUtility getMapUtility() {
        return mapUtility;
    }

    /**
     * Sets the map utility.
     * 
     * @param mapUtility
     *          the new map utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setMapUtility(com.p5solutions.core.jpa.orm.MapUtility )
     */
    @Override
    public void setMapUtility(MapUtility mapUtility) {
        this.mapUtility = mapUtility;
    }

    /**
     * Sets the transaction template.
     * 
     * @param transactionTemplate
     *          the new transaction template
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setTransactionTemplate(com.p5solutions.core.
     *      orm.transaction.TransactionTemplate)
     */
    @Override
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    /**
     * Gets the transaction template.
     * 
     * @return the transaction template
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getTransactionTemplate()
     */
    @Override
    public TransactionTemplate getTransactionTemplate() {
        return transactionTemplate;
    }

    /**
     * Sets the interceptor utility.
     * 
     * @param interceptorUtility
     *          the new interceptor utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#setInterceptorUtility(com.p5solutions.core.jpa.orm
     *      .InterceptorUtility)
     */
    @Override
    public void setInterceptorUtility(InterceptorUtility interceptorUtility) {
        this.interceptorUtility = interceptorUtility;
    }

    /**
     * Gets the interceptor utility.
     * 
     * @return the interceptor utility
     * @see com.p5solutions.core.jpa.orm.EntityPersister#getInterceptorUtility()
     */
    @Override
    public InterceptorUtility getInterceptorUtility() {
        return interceptorUtility;
    }

    /**
     * @return
     */
    public Boolean getFetchBeforeSave() {
        return fetchBeforeSave;
    }

    /**
     * @param fetchBeforeSave
     */
    public void setFetchBeforeSave(Boolean fetchBeforeSave) {
        this.fetchBeforeSave = fetchBeforeSave;
    }

}