org.vulpe.controller.AbstractVulpeBaseController.java Source code

Java tutorial

Introduction

Here is the source code for org.vulpe.controller.AbstractVulpeBaseController.java

Source

/**
 * Vulpe Framework - Quick and Smart ;)
 * Copyright (C) 2011 Active Thread
 *
 * Este programa  software livre; voc pode redistribu-lo e/ou
 * modific-lo sob os termos da Licena Pblica Geral GNU, conforme
 * publicada pela Free Software Foundation; tanto a verso 2 da
 * Licena como (a seu critrio) qualquer verso mais nova.
 *
 * Este programa  distribudo na expectativa de ser til, mas SEM
 * QUALQUER GARANTIA; sem mesmo a garantia implcita de
 * COMERCIALIZAO ou de ADEQUAO A QUALQUER PROPSITO EM
 * PARTICULAR. Consulte a Licena Pblica Geral GNU para obter mais
 * detalhes.
 *
 * Voc deve ter recebido uma cpia da Licena Pblica Geral GNU
 * junto com este programa; se no, escreva para a Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */
/**
 * Vulpe Framework - Quick and Smart ;)
 * Copyright (C) 2011 Active Thread
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.vulpe.controller;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.vulpe.commons.VulpeConstants.Configuration.Ever;
import org.vulpe.commons.VulpeConstants.Configuration.Now;
import org.vulpe.commons.VulpeConstants.Controller;
import org.vulpe.commons.VulpeConstants.Controller.Button;
import org.vulpe.commons.VulpeConstants.Controller.Result;
import org.vulpe.commons.VulpeConstants.Controller.URI;
import org.vulpe.commons.VulpeConstants.Error;
import org.vulpe.commons.VulpeConstants.Model.Entity;
import org.vulpe.commons.VulpeConstants.Upload.File;
import org.vulpe.commons.VulpeConstants.View.Layout;
import org.vulpe.commons.VulpeContext;
import org.vulpe.commons.annotations.Quantity.QuantityType;
import org.vulpe.commons.beans.DownloadInfo;
import org.vulpe.commons.beans.Paging;
import org.vulpe.commons.helper.VulpeConfigHelper;
import org.vulpe.commons.util.VulpeHashMap;
import org.vulpe.commons.util.VulpeReflectUtil;
import org.vulpe.commons.util.VulpeValidationUtil;
import org.vulpe.controller.commons.DuplicatedBean;
import org.vulpe.controller.commons.EverParameter;
import org.vulpe.controller.commons.I18NService;
import org.vulpe.controller.commons.VulpeBaseControllerConfig;
import org.vulpe.controller.commons.VulpeBaseDetailConfig;
import org.vulpe.controller.commons.VulpeControllerConfig.ControllerType;
import org.vulpe.controller.util.VulpeUtil;
import org.vulpe.controller.util.VulpeUtil.VulpeControllerUtil;
import org.vulpe.controller.util.VulpeUtil.VulpeViewUtil;
import org.vulpe.controller.util.VulpeUtil.VulpeViewUtil.VulpeViewContentUtil;
import org.vulpe.controller.validator.EntityValidator;
import org.vulpe.exception.VulpeSystemException;
import org.vulpe.model.annotations.Autocomplete;
import org.vulpe.model.annotations.CachedClass;
import org.vulpe.model.annotations.NotDeleteIf;
import org.vulpe.model.annotations.NotExistEquals;
import org.vulpe.model.annotations.QueryParameter;
import org.vulpe.model.entity.VulpeEntity;
import org.vulpe.model.services.GenericService;
import org.vulpe.model.services.VulpeService;

/**
 * Base Controller
 *
 * @author <a href="mailto:felipe@vulpe.org">Geraldo Felipe</a>
 * @version 1.0
 * @since 1.0
 */
@SuppressWarnings({ "unchecked", "serial", "rawtypes" })
public abstract class AbstractVulpeBaseController<ENTITY extends VulpeEntity<ID>, ID extends Serializable & Comparable<?>>
        implements VulpeController {

    protected static final Logger LOG = LoggerFactory.getLogger(AbstractVulpeBaseController.class);

    @Autowired
    public I18NService i18nService;

    @Autowired
    public VulpeContext vulpeContext;

    public Collection<String> actionInfoMessages = new ArrayList<String>();

    /**
     * Global attributes map
     */
    public EverParameter ever = null;

    /**
     * Temporal attributes map
     */
    public VulpeHashMap<String, Object> now = new VulpeHashMap<String, Object>();

    /**
     *
     */
    public VulpeUtil<ENTITY, ID> vulpe;

    /**
     * Calendar
     */
    public final Calendar calendar = Calendar.getInstance();

    {
        now.put(Now.SYSTEM_DATE, calendar.getTime());
        now.put(Now.CURRENT_LAST_DAY, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        now.put(Now.CURRENT_DAY, calendar.get(Calendar.DAY_OF_MONTH));
        now.put(Now.CURRENT_MONTH, calendar.get(Calendar.MONTH));
        now.put(Now.CURRENT_YEAR, calendar.get(Calendar.YEAR));
    }

    /**
     * Used to set and/or initialize variables in the controller. On this point
     * the components controlled by Spring are now available.
     */
    @PostConstruct
    protected void postConstruct() {
        ever = EverParameter.getInstance(getSession());
        vulpe = new VulpeUtil<ENTITY, ID>(this);
        final VulpeControllerUtil controller = vulpe.controller();
        final VulpeBaseControllerConfig<ENTITY, ID> config = controller.config();
        final VulpeViewUtil view = vulpe.view();
        view.maxInactiveInterval(getSession().getMaxInactiveInterval());
        view.formName(config.getFormName());
        if (config.isRequireOneFilter()) {
            view.requireOneFilter();
        }
        final VulpeViewContentUtil content = view.content();
        content.titleKey(config.getTitleKey());
        if (VulpeValidationUtil.isNotEmpty(config.getDetails())) {
            content.masterTitleKey(config.getMasterTitleKey());
        }
        if (controller.type().equals(ControllerType.REPORT)) {
            content.reportTitleKey(config.getReportTitleKey());
        }
        if (!controller.currentName().endsWith(URI.AUTHENTICATOR)) {
            vulpe.securityContext();
        }
    }

    /**
     * List of entities
     */
    public List<ENTITY> entities = new ArrayList<ENTITY>();
    /**
     * Current MAIN Entity
     */
    public ENTITY entity;
    /**
     * Current Select entity
     */
    public ENTITY entitySelect;
    /**
     * Identifier for selections
     */
    public ID id;
    /**
     * Paginated Bean
     */
    public Paging<ENTITY> paging;

    /**
     * Extension point to report load.
     *
     * @since 1.0
     */
    protected abstract DownloadInfo doReportLoad();

    /**
     * Method to validate quantity of details.
     *
     * @param beans
     * @param detailConfig
     * @return
     */
    protected boolean validateQuantity(final List<ENTITY> beans, final VulpeBaseDetailConfig detailConfig) {
        if (detailConfig.getQuantity() != null) {
            final String tabName = vulpe.view().tabs().containsKey(detailConfig.getTitleKey())
                    ? vulpe.view().tabs().get(detailConfig.getTitleKey()).getTitle()
                    : vulpe.controller().text(detailConfig.getTitleKey());
            if (detailConfig.getQuantity().minimum() > 1 && detailConfig.getQuantity().maximum() > 1
                    && detailConfig.getQuantity().minimum() < detailConfig.getQuantity().maximum()) {
                if (beans == null || beans.size() < detailConfig.getQuantity().minimum()
                        || beans.size() > detailConfig.getQuantity().maximum()) {
                    if (detailConfig.getQuantity().minimum() == detailConfig.getQuantity().maximum()) {
                        addActionError("vulpe.error.details.cardinality.custom.equal",
                                vulpe.controller().text(detailConfig.getTitleKey()),
                                detailConfig.getQuantity().minimum());
                    } else {
                        addActionError("vulpe.error.details.cardinality.custom", tabName,
                                detailConfig.getQuantity().minimum(), detailConfig.getQuantity().maximum());
                    }
                    return false;
                }
            } else if (detailConfig.getQuantity().minimum() > 1 && detailConfig.getQuantity().maximum() == 0
                    && (beans == null || beans.size() < detailConfig.getQuantity().minimum())) {
                addActionError("vulpe.error.details.cardinality.custom.minimum", tabName,
                        detailConfig.getQuantity().minimum());
                return false;
            } else if (detailConfig.getQuantity().minimum() == 0 && detailConfig.getQuantity().maximum() > 1
                    && (beans == null || beans.size() > detailConfig.getQuantity().maximum())) {
                addActionError("vulpe.error.details.cardinality.custom.maximum", tabName,
                        detailConfig.getQuantity().maximum());
                return false;
            } else {
                if (QuantityType.ONE.equals(detailConfig.getQuantity().type())
                        || (detailConfig.getQuantity().minimum() == 1
                                && detailConfig.getQuantity().maximum() == 1)) {
                    boolean valid = true;
                    if (beans == null || beans.size() == 0) {
                        addActionError("vulpe.error.details.cardinality.one.less", tabName);
                        valid = false;
                    } else if (beans.size() > 1) {
                        addActionError("vulpe.error.details.cardinality.one.only", tabName);
                        valid = false;
                    }
                    return valid;
                } else if (QuantityType.ONE_OR_MORE.equals(detailConfig.getQuantity().type())
                        && (beans == null || beans.size() == 0)) {
                    addActionError("vulpe.error.details.cardinality.one.more", tabName);
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Method to check duplicated details.
     *
     * @param parent
     *            Parent
     * @param baseEntity
     * @param detailConfig
     *            Configuration of detail.
     *
     * @since 1.0
     */
    protected abstract boolean duplicatedDetail(final Object parent, final ENTITY baseEntity,
            final VulpeBaseDetailConfig detailConfig);

    /**
     * Method to validate duplicated details.
     *
     * @param beans
     * @param detailConfig
     * @return
     */
    protected boolean duplicatedDetailItens(final Collection<VulpeEntity<?>> beans,
            final VulpeBaseDetailConfig detailConfig) {
        final String[] despiseFields = detailConfig.getDespiseFields();
        final Collection<DuplicatedBean> duplicatedBeans = vulpe.controller().duplicatedItens(beans, despiseFields);
        if (duplicatedBeans != null && !duplicatedBeans.isEmpty()) {
            if (vulpe.controller().type().equals(ControllerType.TABULAR) && duplicatedBeans.size() == 1) {
                return false;
            }
            final StringBuilder lines = new StringBuilder();
            int count = 1;
            for (DuplicatedBean duplicatedBean : duplicatedBeans) {
                if (duplicatedBeans.size() > 1 && duplicatedBeans.size() == count) {
                    lines.append(
                            " " + vulpe.controller().text("label.vulpe.and") + " " + duplicatedBean.getRowNumber());
                } else {
                    lines.append(
                            StringUtils.isBlank(lines.toString()) ? String.valueOf(duplicatedBean.getRowNumber())
                                    : ", " + duplicatedBean.getRowNumber());
                }
                ++count;
            }
            if (vulpe.controller().type().equals(ControllerType.TABULAR)) {
                addActionError("vulpe.error.tabular.duplicated", lines.toString());
            } else {
                final String tabName = vulpe.view().tabs().containsKey(detailConfig.getTitleKey())
                        ? vulpe.view().tabs().get(detailConfig.getTitleKey()).getTitle()
                        : vulpe.controller().text(detailConfig.getTitleKey());
                if (detailConfig.getParentDetailConfig() != null) {
                    final String parentTabName = vulpe.view().tabs()
                            .containsKey(detailConfig.getParentDetailConfig().getTitleKey())
                                    ? vulpe.view().tabs().get(detailConfig.getParentDetailConfig().getTitleKey())
                                            .getTitle()
                                    : vulpe.controller().text(detailConfig.getParentDetailConfig().getTitleKey());
                    addActionError("vulpe.error.subdetails.duplicated.tab", tabName, parentTabName,
                            lines.toString());
                } else {
                    addActionError("vulpe.error.details.duplicated.tab", tabName, lines.toString());
                }
            }
            return true;
        }
        return false;
    }

    /**
     * Method to remove detail despised.
     *
     * @param beans
     *            details
     * @param detailConfig
     *            Configuration of detail.
     *
     * @since 1.0
     */
    protected List<VulpeEntity<?>> despiseDetailItens(final Collection<VulpeEntity<?>> beans,
            final VulpeBaseDetailConfig detailConfig) {
        return vulpe.controller().despiseItens(beans, detailConfig.getDespiseFields(),
                vulpe.controller().type().equals(ControllerType.TABULAR));
    }

    /**
     * Method to remove detail despised.
     *
     * @param parent
     *            Parent
     * @param detailConfig
     *            Configuration of detail.
     *
     * @since 1.0
     */
    protected abstract void despiseDetail(final Object parent, final ENTITY baseEntity,
            final VulpeBaseDetailConfig detailConfig);

    /**
     * Validate if entity already exists
     *
     * @return
     */
    protected boolean validateNotExistEquals() {
        return vulpe.service(GenericService.class).notExistEquals(entity);
    }

    /**
     *
     */
    private void manageButtons() {
        manageButtons(vulpe.controller().operation());
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.vulpe.controller.VulpeController#manageButtons(org.vulpe.controller
     * .VulpeSimpleController.Operation)
     */
    public void manageButtons(final Operation operation) {
        vulpe.view().buttons().clear();
        vulpe.controller().popup();
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (vulpe.controller().type().equals(ControllerType.MAIN)) {
            if (config.getDetails() != null) {
                for (final VulpeBaseDetailConfig detail : config.getDetails()) {
                    if (Operation.VIEW.equals(operation)) {
                        vulpe.view().notRenderDetailButtons(detail.getBaseName(), Button.ADD_DETAIL, Button.DELETE);
                    } else {
                        vulpe.view().renderDetailButtons(detail.getBaseName(), Button.ADD_DETAIL, Button.DELETE);
                    }
                }
            }
            if ((Operation.CREATE.equals(operation) || Operation.DELETE.equals(operation)
                    || Operation.PREPARE.equals(operation))
                    || ((Operation.CREATE.equals(vulpe.controller().operation())
                            || Operation.CREATE_POST.equals(vulpe.controller().operation()))
                            && Operation.ADD_DETAIL.equals(operation))) {
                vulpe.view().renderButtons(Button.BACK, Button.CREATE_POST, Button.CLEAR);
            } else if (Operation.UPDATE.equals(operation)
                    || ((Operation.UPDATE.equals(vulpe.controller().operation())
                            || Operation.UPDATE_POST.equals(vulpe.controller().operation()))
                            && Operation.ADD_DETAIL.equals(operation))) {
                vulpe.view().renderButtons(Button.BACK, Button.CREATE, Button.UPDATE_POST, Button.DELETE);
                if (VulpeConfigHelper.getApplicationConfiguration().view().layout().showButtonClone()) {
                    vulpe.view().renderButtons(Button.CLONE);
                }
            } else if (Operation.VIEW.equals(operation)) {
                vulpe.view().renderButtons();
            }
        } else if (vulpe.controller().type().equals(ControllerType.SELECT)) {
            vulpe.view().renderButtons(Button.READ, Button.CLEAR, Button.CREATE, Button.UPDATE, Button.DELETE);
            if (config.getControllerAnnotation().select().showReport()) {
                vulpe.view().renderButtons(Button.REPORT);
            } else {
                vulpe.view().notRenderButtons(Button.REPORT);
            }
            if (vulpe.controller().popup()) {
                vulpe.view().notRenderButtons(Button.CREATE, Button.UPDATE, Button.DELETE);
            }
        } else if (vulpe.controller().type().equals(ControllerType.REPORT)) {
            vulpe.view().renderButtons(Button.READ, Button.CLEAR);
        } else if (vulpe.controller().type().equals(ControllerType.TABULAR)) {
            vulpe.view().renderButtons(Button.TABULAR_RELOAD, Button.DELETE, Button.TABULAR_POST,
                    Button.ADD_DETAIL);
            if (config.isTabularShowFilter()) {
                vulpe.view().renderButtons(Button.TABULAR_FILTER);
            }
        } else if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            if (Operation.DELETE.equals(operation) || Operation.CREATE.equals(operation)
                    || Operation.TWICE.equals(operation)) {
                vulpe.view().renderButtons(ControllerType.MAIN, Button.CREATE_POST, Button.CLEAR);
            } else if (Operation.UPDATE.equals(operation)) {
                vulpe.view().renderButtons(ControllerType.MAIN, Button.CREATE, Button.UPDATE_POST, Button.DELETE);
                if (VulpeConfigHelper.getApplicationConfiguration().view().layout().showButtonClone()) {
                    vulpe.view().renderButtons(Button.CLONE);
                }
            } else if (Operation.VIEW.equals(operation)) {
                vulpe.view().renderButtons();
            }
            vulpe.view().renderButtons(ControllerType.SELECT, Button.READ, Button.BACK, Button.UPDATE,
                    Button.DELETE);
        }
    }

    /**
     * Method to show error
     *
     * @param message
     * @return
     */
    protected void showError(final String message) {
        manageButtons(vulpe.controller().operation());
        addActionError(message);
        controlResultForward();
    }

    protected abstract boolean validateDetails();

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeSimpleController#validateEntity()
     */
    public boolean validateEntity() {
        if ((vulpe.controller().operation().equals(Operation.CREATE_POST)
                || vulpe.controller().operation().equals(Operation.UPDATE_POST))) {
            if (validateNotExistEquals()) {
                final NotExistEquals notExistEqual = vulpe.controller().config().getEntityClass()
                        .getAnnotation(NotExistEquals.class);
                String message = "{vulpe.error.entity.exists}";
                if (StringUtils.isNotEmpty(notExistEqual.message())) {
                    message = notExistEqual.message();
                }
                addActionError(message);
                return false;
            }
            managePaging(false);
        }
        return EntityValidator.validate(entity) && validateDetails();
    }

    /**
     *
     * @param persisted
     */
    private void managePaging(final boolean persisted) {
        for (final VulpeBaseDetailConfig detailConfig : vulpe.controller().config().getDetails()) {
            if (vulpe.controller().deleted()) {
                vulpe.controller().removeDetailPaging(detailConfig.getName());
                prepareDetailPaging();
            } else {
                final List<ENTITY> details = VulpeReflectUtil.getFieldValue(entity,
                        detailConfig.getParentDetailConfig() != null
                                ? detailConfig.getParentDetailConfig().getName()
                                : detailConfig.getName());
                if (detailConfig.getPageSize() > 0 && detailConfig.getPropertyName().startsWith("entity.")) {
                    final Paging<ENTITY> paging = vulpe.controller().detailPaging(detailConfig.getName());
                    if (persisted) {
                        paging.setRealList(details);
                    } else {
                        repairDetailPaging(details, paging);
                        details.clear();
                        if (VulpeValidationUtil.isNotEmpty(paging)
                                && VulpeValidationUtil.isNotEmpty(paging.getRealList())) {
                            details.addAll(paging.getRealList());
                            for (final ENTITY entity : details) {
                                if (entity.isFakeId()) {
                                    entity.setId(null);
                                }
                            }
                        }
                    }
                    mountDetailPaging(detailConfig, paging);
                }
            }
        }
    }

    protected void tabularPagingMount(final boolean add) {
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (vulpe.controller().type().equals(ControllerType.TABULAR) && config.getTabularPageSize() > 0) {
            if (add) {
                vulpe.controller().tabularSize(
                        vulpe.controller().tabularSize() + config.getControllerAnnotation().tabular().newRecords());
            } else {
                vulpe.controller().tabularSize(entities.size());
            }
            Integer page = vulpe.controller().currentPage();
            if (paging != null) {
                page = paging.getPage();
            }
            if (page == null) {
                page = 0;
            }
            paging = new Paging<ENTITY>(vulpe.controller().tabularSize(),
                    vulpe.controller().config().getTabularPageSize(), page);
            paging.setList(entities);
        }
    }

    public void json() {
        final Object object = onJson();
        if (VulpeValidationUtil.isNotEmpty(object)) {
            vulpe.controller().renderJSON(object);
        }
    }

    protected Object onJson() {
        return null;
    }

    protected void autocompleteBefore() {
        // extension point
    }

    protected void autocompleteAfter() {
        // extension point
    }

    public void autocomplete() {
        autocompleteBefore();
        String value = "";
        final ENTITY autocompleteEntity = (ENTITY) prepareEntity(Operation.READ).clone();
        if (StringUtils.isBlank(autocompleteEntity.getQueryConfigurationName())) {
            autocompleteEntity.setQueryConfigurationName("autocomplete");
        }
        List<VulpeHashMap<String, Object>> values = autocompleteValueList();
        if (VulpeValidationUtil.isEmpty(values)) {
            List<ENTITY> autocompleteList = autocompleteList();
            String description = autocompleteEntity.getAutocomplete();
            if (description.contains(",")) {
                autocompleteEntity.setAutocomplete(description.substring(description.indexOf(',') + 1));
                description = description.substring(0, description.indexOf(','));
            }

            if (VulpeValidationUtil.isEmpty(autocompleteList)) {
                autocompleteList = (List<ENTITY>) invokeServices(vulpe.serviceMethodName(Operation.READ),
                        new Class[] { vulpe.controller().config().getEntityClass() },
                        new Object[] { autocompleteEntity });
            }
            values = new ArrayList<VulpeHashMap<String, Object>>();
            if (VulpeValidationUtil.isNotEmpty(autocompleteList)) {
                final List<Field> autocompleteFields = VulpeReflectUtil
                        .getFieldsWithAnnotation(vulpe.controller().config().getEntityClass(), Autocomplete.class);
                for (final ENTITY entity : autocompleteList) {
                    final VulpeHashMap<String, Object> map = new VulpeHashMap<String, Object>();
                    try {
                        map.put("id", entity.getId());
                        map.put("value", PropertyUtils.getProperty(entity, description));
                        if (VulpeValidationUtil.isNotEmpty(autocompleteFields)) {
                            for (final Field field : autocompleteFields) {
                                if (!field.getName().equals(entitySelect.getAutocomplete())) {
                                    map.put(field.getName(), PropertyUtils.getProperty(entity, field.getName()));
                                }
                            }
                        }
                        if (entitySelect.getId() != null) {
                            value = map.getAuto("value");
                            break;
                        }
                    } catch (Exception e) {
                        LOG.error(e.getMessage());
                    }
                    values.add(map);
                }
            } else {
                vulpe.controller().renderPlainText("");
            }
        } else if (entitySelect.getId() != null) {
            for (final VulpeHashMap<String, Object> map : values) {
                final Long id = map.getAuto("id");
                if (id.equals(entitySelect.getId())) {
                    value = map.getAuto("value");
                    break;
                }
            }
        }
        autocompleteAfter();
        if (entitySelect.getId() == null) {
            vulpe.controller().renderJSON(values);
        } else {
            vulpe.controller().renderPlainText(value);
        }
    }

    protected List<ENTITY> autocompleteList() {
        return null;
    }

    protected List<VulpeHashMap<String, Object>> autocompleteValueList() {
        return null;
    }

    /**
     * Extension point to prepare entity.
     *
     * @since 1.0
     */
    protected ENTITY prepareEntity(final Operation operation) {
        ENTITY currentEntity = Operation.READ.equals(operation) ? entitySelect : this.entity;
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        try {
            if (operation.equals(Operation.SELECT) || operation.equals(Operation.CREATE)) {
                currentEntity = config.getEntityClass().newInstance();
            } else if (currentEntity == null) {
                currentEntity = config.getEntityClass().newInstance();
            }
            vulpe.updateAuditInfo(currentEntity);
            if (Operation.READ.equals(operation) && entitySelect == null) {
                entitySelect = config.getEntityClass().newInstance();
                currentEntity = entitySelect;
            } else if (entitySelect != null && StringUtils.isNotEmpty(entitySelect.getAutocomplete())) {
                if (id != null && entitySelect.getId() == null) {
                    entitySelect.setId(id);
                }
            } else if (Operation.UPDATE.equals(operation) || (Operation.DELETE.equals(operation)
                    && (vulpe.controller().type().equals(ControllerType.SELECT)
                            || vulpe.controller().type().equals(ControllerType.TABULAR)
                            || vulpe.controller().type().equals(ControllerType.TWICE)))) {
                currentEntity.setId(id);
            }
        } catch (Exception e) {
            throw new VulpeSystemException(e);
        }
        if (StringUtils.isEmpty(currentEntity.getQueryConfigurationName())
                || "default".equals(currentEntity.getQueryConfigurationName())) {
            currentEntity.setQueryConfigurationName(config.getControllerAnnotation().queryConfigurationName());
        }
        return currentEntity;
    }

    /**
     * Extension point to prepare detail.
     *
     * @param detail
     *            Detail.
     * @since 1.0
     */
    protected ENTITY prepareDetail(final ENTITY detail) {
        return detail;
    }

    protected void orderDetails() {
        for (final VulpeBaseDetailConfig detailConfig : vulpe.controller().config().getDetails()) {
            final List<ENTITY> details = VulpeReflectUtil.getExpressionValue(this, detailConfig.getPropertyName());
            if (VulpeValidationUtil.isNotEmpty(details)) {
                for (final Iterator<ENTITY> iterator = details.iterator(); iterator.hasNext();) {
                    final ENTITY entity = iterator.next();
                    if (entity == null) {
                        iterator.remove();
                    }
                }
                Collections.sort(details);
            }
        }
    }

    /**
     * Configure detail to view.
     */
    protected void configureDetail() {
        vulpe.view().targetConfig(vulpe.controller().detailConfig());
        vulpe.view().targetConfigPropertyName(vulpe.controller().detail());
    }

    protected void mountDetailPaging(final VulpeBaseDetailConfig detailConfig, final Paging<ENTITY> currentPaging) {
        mountPaging(currentPaging, detailConfig.getPageSize());
    }

    protected void mountPaging(final Paging<ENTITY> currentPaging, final int pageSize) {
        final List<ENTITY> list = new ArrayList<ENTITY>();
        if (paging != null && paging.getPage() != null) {
            currentPaging.setPage(paging.getPage());
        }
        if (VulpeValidationUtil.isNotEmpty(currentPaging)
                && VulpeValidationUtil.isNotEmpty(currentPaging.getRealList())) {
            int count = 1;
            int total = 0;
            for (final ENTITY entity : currentPaging.getRealList()) {
                if (count > ((currentPaging.getPage() - 1) * currentPaging.getPageSize())) {
                    if (total == pageSize) {
                        break;
                    }
                    list.add(entity);
                    ++total;
                }
                ++count;
            }
            currentPaging.processPage();
            currentPaging.setList(list);
        }
    }

    protected void repairDetailPaging(final List<ENTITY> values, final Paging<ENTITY> paging) {
        if (VulpeValidationUtil.isNotEmpty(values) && VulpeValidationUtil.isNotEmpty(paging)
                && VulpeValidationUtil.isNotEmpty(paging.getRealList())) {
            int index = 0;
            for (final ENTITY real : paging.getRealList()) {
                for (final ENTITY modified : values) {
                    if (VulpeValidationUtil.isNotEmpty(modified)
                            && (real.getId() != null && real.getId().equals(modified.getId()))) {
                        paging.getRealList().set(index, modified);
                        break;
                    }
                }
                ++index;
            }
        }
    }

    public void paging() {
        pagingBefore();
        if (VulpeValidationUtil.isNotEmpty(vulpe.controller().detail())) {
            final Paging<ENTITY> paging = vulpe.controller().detailPaging();
            final List<ENTITY> values = VulpeReflectUtil.getFieldValue(entity, vulpe.controller().detail());
            repairDetailPaging(values, paging);
            if (!vulpe.controller().detail().startsWith("entity")) {
                vulpe.controller().detail("entity." + vulpe.controller().detail());
            }
            configureDetail();
            final VulpeBaseDetailConfig detailConfig = vulpe.controller().detailConfig();
            mountDetailPaging(detailConfig, paging);
            manageButtons(Operation.ADD_DETAIL);
            if (vulpe.controller().ajax()) {
                if (detailConfig == null || detailConfig.getViewPath() == null) {
                    controlResultForward();
                } else {
                    vulpe.controller().resultForward(detailConfig.getViewPath());
                }
            }
        }
        pagingAfter();
    }

    protected void pagingBefore() {
    }

    protected void pagingAfter() {
    }

    protected void prepareDetailPaging() {
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (VulpeValidationUtil.isNotEmpty(config.getDetails())) {
            for (final VulpeBaseDetailConfig detailConfig : config.getDetails()) {
                if (detailConfig.getPageSize() > 0 && detailConfig.getPropertyName().startsWith("entity.")) {
                    final List<ENTITY> values = VulpeReflectUtil.getFieldValue(entity, detailConfig.getName());
                    if (VulpeValidationUtil.isNotEmpty(values)) {
                        int id = 1;
                        for (final ENTITY entity : values) {
                            if (entity.getId() == null) {
                                entity.setId((ID) new Long(id));
                                entity.setFakeId(true);
                                ++id;
                            }
                        }
                        final List<ENTITY> list = new ArrayList<ENTITY>();
                        int count = 0;
                        for (final ENTITY entity : values) {
                            if (count == detailConfig.getPageSize()) {
                                break;
                            }
                            list.add(entity);
                            ++count;
                        }
                        final Paging<ENTITY> paging = new Paging<ENTITY>(values.size(), detailConfig.getPageSize(),
                                0);
                        paging.setList(list);
                        paging.setRealList(values);
                        vulpe.controller().detailPaging(detailConfig.getName(), paging);
                    }
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#addDetail()
     */
    public void addDetail() {
        addDetailBefore();
        final VulpeBaseDetailConfig detailConfig = onAddDetail(false);
        configureDetail();
        manageButtons(Operation.ADD_DETAIL);
        if (vulpe.controller().ajax()) {
            if (detailConfig == null || detailConfig.getViewPath() == null) {
                controlResultForward();
            } else {
                vulpe.controller().resultForward(detailConfig.getViewPath());
            }
        } else {
            controlResultForward();
        }
        addDetailAfter();
    }

    /**
     * Extension point to code before add detail.
     *
     * @since 1.0
     */
    protected void addDetailBefore() {
        if (!vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TABULAR)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after add detail.
     *
     * @since 1.0
     */
    protected void addDetailAfter() {
        // extension point
    }

    protected abstract VulpeBaseDetailConfig onAddDetail(final boolean start);

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#clear()
     */
    public void clear() {
        // vulpe.controller().cleaned(true);
        if (vulpe.controller().type().equals(ControllerType.MAIN)) {
            entitySelect = prepareEntity(Operation.CREATE);
            create();
        } else if (vulpe.controller().type().equals(ControllerType.SELECT)) {
            ever.remove(vulpe.controller().selectFormKey());
            ever.remove(vulpe.controller().selectTableKey());
            ever.remove(vulpe.controller().selectPagingKey());
            entitySelect = prepareEntity(Operation.SELECT);
            select();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#create()
     */
    public void create() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().type(ControllerType.MAIN);
        }
        vulpe.controller().operation(Operation.CREATE);
        createBefore();
        onCreate();
        vulpe.controller().selectedTab(null);
        manageButtons(Operation.CREATE);
        if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.view().bodyTwice(ControllerType.MAIN);
            vulpe.controller().resultForward(Layout.PROTECTED_JSP_COMMONS.concat(Layout.BODY_JSP));
        } else {
            controlResultForward();
        }
        createAfter();
    }

    /**
     * Extension point to create record.
     *
     * @since 1.0
     */
    protected void onCreate() {
        if (vulpe.controller().type().equals(ControllerType.MAIN)
                || vulpe.controller().type().equals(ControllerType.TWICE)) {
            final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
            try {
                entity = config.getEntityClass().newInstance();
                entity = prepareEntity(vulpe.controller().operation());
                if (VulpeValidationUtil.isNotEmpty(config.getDetails())) {
                    createDetails(config.getDetails(), false);
                    vulpe.controller().detail("");
                }
                prepareDetailPaging();
            } catch (Exception e) {
                throw new VulpeSystemException(e);
            }
            vulpe.controller().executed(false);
        }
    }

    /**
     * Extension point to code before create.
     *
     * @since 1.0
     */
    protected void createBefore() {
        if (!vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TWICE)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after create.
     *
     * @since 1.0
     */
    protected void createAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#cloneIt()
     */
    public void cloneIt() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().type(ControllerType.MAIN);
        }
        vulpe.controller().operation(Operation.CLONE);
        cloneItBefore();
        if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.view().bodyTwice(ControllerType.MAIN);
            vulpe.controller().resultForward(Layout.PROTECTED_JSP_COMMONS.concat(Layout.BODY_JSP));
        } else {
            controlResultForward();
        }
        if (onCloneIt()) {
            manageButtons(Operation.CREATE);
            addActionMessage(vulpe.controller().defaultMessage());
            vulpe.controller().selectedTab(null);
            cloneItAfter();
        }
    }

    /**
     * Extension point to clone record.
     *
     * @since 1.0
     */
    protected boolean onCloneIt() {
        if (vulpe.controller().type().equals(ControllerType.MAIN)
                || vulpe.controller().type().equals(ControllerType.TWICE)) {
            try {
                entity = (ENTITY) entity.clone();
                entity.setId(null);
            } catch (Exception e) {
                throw new VulpeSystemException(e);
            }
            vulpe.controller().executed(false);
        }
        return true;
    }

    /**
     * Extension point to code before clone.
     *
     * @since 1.0
     */
    protected void cloneItBefore() {
        if (!vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TWICE)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after clone.
     *
     * @since 1.0
     */
    protected void cloneItAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#createPost()
     */
    public void createPost() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().type(ControllerType.MAIN);
        }
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        vulpe.controller().operation(Operation.CREATE_POST);
        createPostBefore();
        controlResultForward();
        if (validateEntity() && onCreatePost()) {
            manageButtons(Operation.UPDATE);
            orderDetails();
            addActionMessage(vulpe.controller().defaultMessage());
            if (config.getEntityClass().isAnnotationPresent(CachedClass.class) && validateCacheClass(entity)) {
                final String entityName = config.getEntityClass().getSimpleName();
                List<ENTITY> list = (List<ENTITY>) vulpe.cache().classes().get(entityName);
                if (VulpeValidationUtil.isEmpty(list)) {
                    list = new ArrayList<ENTITY>();
                }
                list.add(entity);
                Collections.sort(list);
                vulpe.cache().classes().put(entityName, list);
            }
            createPostAfter();
            if (vulpe.controller().type().equals(ControllerType.TWICE)) {
                onRead();
            }
        } else {
            prepareDetailPaging();
            manageButtons(Operation.CREATE);
        }
        if (config.isNewOnPost()) {
            create();
        }
    }

    /**
     * Extension point to code in confirm create.
     *
     * @since 1.0
     * @return Entity created.
     */
    protected boolean onCreatePost() {
        updateDetailsAuditInfo();
        entity = (ENTITY) invokeServices(vulpe.serviceMethodName(Operation.CREATE),
                new Class[] { vulpe.controller().config().getEntityClass() },
                new Object[] { prepareEntity(Operation.CREATE_POST) });
        id = entity.getId();
        managePaging(true);
        vulpe.controller().executed(true);
        return true;
    }

    /**
     * Extension point to code before confirm create.
     *
     * @since 1.0
     */
    protected void createPostBefore() {
        if (!vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TWICE)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after confirm create.
     *
     * @since 1.0
     */
    protected void createPostAfter() {
        // extension point
    }

    protected abstract void createDetails(final List<VulpeBaseDetailConfig> details, final boolean subDetail);

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#update()
     */
    public void update() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().type(ControllerType.MAIN);
        }
        vulpe.controller().operation(Operation.UPDATE);
        updateBefore();
        if (entity == null && id == null) {
            create();
        }
        onUpdate();
        vulpe.controller().selectedTab(null);
        manageButtons();
        if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.view().bodyTwice(ControllerType.MAIN);
            vulpe.controller().resultForward(Layout.PROTECTED_JSP_COMMONS.concat(Layout.BODY_JSP));
        } else {
            controlResultForward();
        }
        updateAfter();
        ever.putWeakRef(Controller.ENTITY_BEFORE_UPDATE, entity.map().get(Entity.UNREFERENCED));
    }

    /**
     * Make visualization read only.
     *
     * @since 1.0
     * @return
     */
    public void view() {
        vulpe.view().onlyToSee(true);
        update();
        manageButtons(Operation.VIEW);
    }

    /**
     * Extension point to prepare update.
     *
     * @since 1.0
     */
    protected void onUpdate() {
        if (vulpe.controller().type().equals(ControllerType.MAIN)
                || vulpe.controller().type().equals(ControllerType.TWICE)) {
            entity = (ENTITY) invokeServices(vulpe.serviceMethodName(Operation.FIND),
                    new Class[] { vulpe.controller().config().getEntityClass() },
                    new Object[] { prepareEntity(vulpe.controller().operation()) });
            prepareDetailPaging();
            orderDetails();
            vulpe.controller().executed(false);
        }
    }

    /**
     * Extension point to code before update.
     *
     * @since 1.0
     */
    protected void updateBefore() {
        if (!vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TWICE)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after update.
     *
     * @since 1.0
     */
    protected void updateAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#updatePost()
     */
    public void updatePost() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().type(ControllerType.MAIN);
        }
        vulpe.controller().operation(Operation.UPDATE_POST);
        updatePostBefore();
        controlResultForward();
        manageButtons(Operation.UPDATE);
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (validateEntity() && onUpdatePost()) {
            orderDetails();
            addActionMessage(vulpe.controller().defaultMessage());
            if (config.getEntityClass().isAnnotationPresent(CachedClass.class)) {
                boolean valid = validateCacheClass(entity);
                final String entityName = config.getEntityClass().getSimpleName();
                List<ENTITY> list = (List<ENTITY>) vulpe.cache().classes().get(entityName);
                if (VulpeValidationUtil.isEmpty(list) && valid) {
                    list = new ArrayList<ENTITY>();
                    list.add(entity);
                } else {
                    int count = 0;
                    boolean exist = false;
                    for (final ENTITY baseEntity : list) {
                        if (baseEntity.getId().equals(entity.getId())) {
                            exist = true;
                            if (valid) {
                                list.set(count, entity);
                            } else {
                                list.remove(count);
                            }
                            break;
                        }
                        ++count;
                    }
                    if (!exist) {
                        list.add(entity);
                    }
                }
                Collections.sort(list);
                vulpe.cache().classes().put(entityName, list);
            }
            if (!config.isOnlyUpdateDetails()) {
                final List<ENTITY> entities = ever.getAuto(vulpe.controller().selectTableKey());
                if (entities != null && !entities.isEmpty()) {
                    final List<ENTITY> entitiesOld = new ArrayList<ENTITY>(entities);
                    int index = 0;
                    for (final ENTITY entity : entitiesOld) {
                        if (entity.getId().equals(entity.getId())) {
                            entities.remove(index);
                            entities.add(index, entity);
                        }
                        ++index;
                    }
                    ever.put(vulpe.controller().selectTableKey(), entities);
                }
            }
            updatePostAfter();
            if (vulpe.controller().type().equals(ControllerType.TWICE)) {
                onRead();
            }
        } else {
            prepareDetailPaging();
        }
    }

    /**
     * Extension point prepare confirm update.
     *
     * @since 1.0
     */
    protected boolean onUpdatePost() {
        final ENTITY entity = prepareEntity(Operation.UPDATE_POST);
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (config.isOnlyUpdateDetails()) {
            final List<String> details = new ArrayList<String>();
            for (final VulpeBaseDetailConfig detailConfig : config.getDetails()) {
                details.add(detailConfig.getName());
            }
            entity.map().put(Entity.ONLY_UPDATE_DETAILS, details);
        }
        entity.map().put(Entity.BEFORE_UPDATE, ever.get(Controller.ENTITY_BEFORE_UPDATE));
        updateDetailsAuditInfo();
        this.entity = (ENTITY) invokeServices(vulpe.serviceMethodName(Operation.UPDATE),
                new Class[] { config.getEntityClass() }, new Object[] { entity });
        managePaging(true);
        vulpe.controller().executed(true);
        return true;
    }

    private void updateDetailsAuditInfo() {
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (VulpeValidationUtil.isNotEmpty(config.getDetails())) {
            for (final VulpeBaseDetailConfig detailConfig : config.getDetails()) {
                final List<ENTITY> details = VulpeReflectUtil.getFieldValue(entity,
                        detailConfig.getParentDetailConfig() != null
                                ? detailConfig.getParentDetailConfig().getName()
                                : detailConfig.getName());
                if (VulpeValidationUtil.isNotEmpty(details)) {
                    if (detailConfig.getParentDetailConfig() == null) {
                        for (final ENTITY detail : details) {
                            vulpe.updateAuditInfo(detail);
                        }
                    } else {
                        for (final ENTITY detail : details) {
                            final List<ENTITY> subDetails = VulpeReflectUtil.getFieldValue(detail,
                                    detailConfig.getName());
                            if (VulpeValidationUtil.isNotEmpty(subDetails)) {
                                for (final ENTITY subDetail : subDetails) {
                                    vulpe.updateAuditInfo(subDetail);
                                }
                                VulpeReflectUtil.setFieldValue(detail, detailConfig.getName(), subDetails);
                            }
                        }
                    }
                    VulpeReflectUtil.setFieldValue(entity, detailConfig.getName(), details);
                }
            }
        }
    }

    /**
     * Extension point to code before confirm update.
     *
     * @since 1.0
     */
    protected void updatePostBefore() {
        if (!vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TWICE)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after confirm update.
     *
     * @since 1.0
     */
    protected void updatePostAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#delete()
     */
    public void delete() {
        vulpe.controller().operation(Operation.DELETE);
        deleteBefore();
        manageButtons();
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (onDelete()) {
            addActionMessage(vulpe.controller().defaultMessage());
            vulpe.controller().selectedTab(null);
            if (config.getEntityClass().isAnnotationPresent(CachedClass.class)) {
                final String entityName = config.getEntityClass().getSimpleName();
                final List<ENTITY> list = (List<ENTITY>) vulpe.cache().classes().get(entityName);
                if (VulpeValidationUtil.isNotEmpty(list)) {
                    for (final Iterator<ENTITY> iterator = list.iterator(); iterator.hasNext();) {
                        final ENTITY currentEntity = iterator.next();
                        if (vulpe.controller().type().equals(ControllerType.SELECT)) {
                            if (VulpeValidationUtil.isNotEmpty(vulpe.controller().selected())) {
                                for (final ID id : vulpe.controller().selected()) {
                                    if (currentEntity.getId().equals(id)) {
                                        iterator.remove();
                                        break;
                                    }
                                }
                            } else if (currentEntity.getId().equals(id)) {
                                iterator.remove();
                            }
                        } else {
                            if (currentEntity.getId().equals(entity.getId())) {
                                iterator.remove();
                            }
                        }
                    }
                }
                vulpe.cache().classes().put(entityName, list);
            }
            try {
                entity = config.getEntityClass().newInstance();
            } catch (Exception e) {
                throw new VulpeSystemException(e);
            }
            deleteAfter();
            vulpe.controller().deleted(true);
            if (vulpe.controller().type().equals(ControllerType.MAIN)) {
                managePaging(false);
                create();
            } else if (vulpe.controller().type().equals(ControllerType.TWICE) && entity.getId() != null) {
                onRead();
                controlResultForward();
            } else {
                read();
            }
        } else {
            if (vulpe.controller().type().equals(ControllerType.MAIN)) {
                controlResultForward();
            } else {
                initPaging();
                vulpe.controller().resultForward(config.getViewItemsPath());
            }
        }
    }

    /**
     * Extension point to delete.
     *
     * @since 1.0
     */
    protected boolean onDelete() {
        boolean valid = true;
        final ENTITY entity = prepareEntity(Operation.DELETE);
        final List<ENTITY> selectedEntities = new ArrayList<ENTITY>();
        if (VulpeValidationUtil.isNotEmpty(vulpe.controller().selected())) {
            if (!onDeleteMany(selectedEntities)) {
                valid = false;
            }
        } else if (vulpe.controller().type().equals(ControllerType.TABULAR)) {
            vulpe.controller().tabularSize(vulpe.controller().tabularSize() - 1);
        } else {
            if (!onDeleteOne()) {
                valid = false;
            }
        }
        if (valid) {
            final NotDeleteIf notDeleteIf = entity.getClass().getAnnotation(NotDeleteIf.class);
            if (VulpeValidationUtil.isNotEmpty(selectedEntities)) {
                invokeServices(vulpe.serviceMethodName(Operation.DELETE), new Class[] { List.class },
                        new Object[] { selectedEntities });
                if (notDeleteIf != null) {
                    final List<Integer> rows = new ArrayList<Integer>();
                    boolean used = false;
                    for (final ENTITY entity2 : selectedEntities) {
                        if (entity2.isUsed()) {
                            for (final ENTITY entity3 : entities) {
                                if (entity2.getId().equals(entity3.getId())) {
                                    rows.add(entity3.getRowNumber());
                                    used = true;
                                }
                            }
                        }
                    }
                    if (rows.isEmpty()) {
                        for (final ENTITY entity2 : selectedEntities) {
                            if (entity2.isConditional()) {
                                for (final ENTITY entity3 : entities) {
                                    if (entity2.getId().equals(entity3.getId())) {
                                        rows.add(entity3.getRowNumber());
                                    }
                                }
                            }
                        }
                    }
                    if (rows.size() > 0) {
                        final StringBuilder affectedRows = new StringBuilder();
                        int count = 1;
                        for (final Integer line : rows) {
                            if (affectedRows.length() > 0) {
                                affectedRows.append(count == rows.size()
                                        ? " " + vulpe.controller().text("label.vulpe.and") + " "
                                        : ", ");
                            }
                            affectedRows.append(line);
                            ++count;
                        }
                        if (rows.size() == 1) {
                            addActionError(
                                    used ? notDeleteIf.usedBy().messageToOneRecordOnSelect()
                                            : notDeleteIf.conditions().messageToOneRecordOnSelect(),
                                    affectedRows.toString());
                        } else {
                            addActionError(
                                    used ? notDeleteIf.usedBy().messageToManyRecordsOnSelect()
                                            : notDeleteIf.conditions().messageToManyRecordsOnSelect(),
                                    affectedRows.toString());
                        }
                        valid = false;
                    }
                }
            } else {
                invokeServices(vulpe.serviceMethodName(Operation.DELETE),
                        new Class[] { vulpe.controller().config().getEntityClass() }, new Object[] { entity });
                if (notDeleteIf != null && (entity.isUsed() || entity.isConditional())) {
                    addActionError(entity.isUsed() ? notDeleteIf.usedBy().messageToRecordOnMain()
                            : notDeleteIf.conditions().messageToRecordOnMain());
                    valid = false;
                }
            }
            vulpe.controller().executed(true);
        }
        return valid;
    }

    protected boolean onDeleteOne() {
        return true;
    }

    protected boolean onDeleteMany(final List<ENTITY> entities) {
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        for (final ID id : vulpe.controller().selected()) {
            try {
                final ENTITY newEntity = config.getEntityClass().newInstance();
                newEntity.setId(id);
                entities.add(newEntity);
            } catch (Exception e) {
                throw new VulpeSystemException(e);
            }
        }
        if (config.getTabularPageSize() > 0) {
            vulpe.controller().tabularSize(
                    vulpe.controller().tabularSize() - (entities.size() - vulpe.controller().selected().size()));
        }
        return true;
    }

    /**
     * Extension point to code before delete.
     *
     * @since
     */
    protected void deleteBefore() {
        if (!vulpe.controller().type().equals(ControllerType.SELECT)
                && !vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TWICE)
                && !vulpe.controller().type().equals(ControllerType.TABULAR)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after delete.
     *
     * @since 1.0
     */
    protected void deleteAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#deleteFile()
     */
    public void deleteFile() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().type(ControllerType.MAIN);
        }
        vulpe.controller().operation(Operation.DELETE_FILE);
        deleteFileBefore();
        controlResultForward();
        manageButtons(Operation.UPDATE);
        if (validateEntity() && onDeleteFile()) {
            addActionMessage(vulpe.controller().defaultMessage());
            deleteFileAfter();
            if (vulpe.controller().type().equals(ControllerType.TWICE)) {
                onRead();
            }
        } else {
            prepareDetailPaging();
        }
    }

    /**
     *
     * @return
     */
    protected boolean onDeleteFile() {
        boolean valid = true;
        if (StringUtils.isNotBlank(vulpe.controller().propertyName())
                && VulpeReflectUtil.fieldExists(entity.getClass(), vulpe.controller().propertyName())) {
            VulpeReflectUtil.setFieldValue(entity, vulpe.controller().propertyName(), null);
            final String contentType = vulpe.controller().propertyName().concat(File.SUFFIX_CONTENT_TYPE);
            if (VulpeReflectUtil.fieldExists(entity.getClass(), contentType)) {
                VulpeReflectUtil.setFieldValue(entity, contentType, null);
            }
            final String fileName = vulpe.controller().propertyName().concat(File.SUFFIX_FILE_NAME);
            if (VulpeReflectUtil.fieldExists(entity.getClass(), fileName)) {
                VulpeReflectUtil.setFieldValue(entity, fileName, null);
            }
            valid = onUpdatePost();
        }

        return valid;
    }

    /**
     * Extension point to code before delete file.
     *
     * @since 1.0
     */
    protected void deleteFileBefore() {
        // extension point
    }

    /**
     * Extension point to code after delete file.
     *
     * @since 1.0
     */
    protected void deleteFileAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#deleteDetail()
     */
    public void deleteDetail() {
        vulpe.controller().operation(Operation.UPDATE_POST);
        deleteDetailBefore();
        manageButtons(Operation.UPDATE);
        final int size = onDeleteDetail();
        configureDetail();
        if (size > 0) {
            // final String defaultMessage =
            // getDefaultMessage(Operation.DELETE_DETAIL);
            addActionMessage(size > 1 ? "{vulpe.message.delete.details}" : "{vulpe.message.delete.detail}");
            if (vulpe.controller().type().equals(ControllerType.TABULAR) && !entities.isEmpty()) {
                final ENTITY entityTabular = entities.get(0);
                if (entityTabular.getClass().isAnnotationPresent(CachedClass.class)) {
                    final String entityName = entityTabular.getClass().getSimpleName();
                    vulpe.cache().classes().put(entityName, entities);
                }
            }
        }
        if (vulpe.controller().ajax()) {
            final VulpeBaseDetailConfig detailConfig = vulpe.controller().config()
                    .getDetailConfig(vulpe.controller().detail());
            if (detailConfig == null || StringUtils.isBlank(detailConfig.getViewPath())) {
                controlResultForward();
            } else {
                vulpe.controller().resultForward(detailConfig.getViewPath());
            }
        } else {
            controlResultForward();
        }
        deleteDetailAfter();
    }

    /**
     * Extension point to delete detail items.
     *
     * @since 1.0
     * @return number of items affected
     */
    protected abstract int onDeleteDetail();

    /**
     * Extension point to code before delete detail items.
     *
     * @since 1.0
     */
    protected void deleteDetailBefore() {
        if (!vulpe.controller().type().equals(ControllerType.SELECT)
                && !vulpe.controller().type().equals(ControllerType.MAIN)
                && !vulpe.controller().type().equals(ControllerType.TABULAR)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after delete detail items.
     *
     * @since 1.0
     */
    protected void deleteDetailAfter() {
        // extension point
    }

    /**
     * Method to read record.
     *
     * @since 1.0
     * @return Navigation.
     */
    public void read() {
        if (vulpe.controller().type() == null || !vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.controller().operation(Operation.READ);
        }
        readBefore();
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (ever.containsKey(Controller.VIRTUAL_PAGING) && VulpeValidationUtil.isNotEmpty(paging)) {
            final Paging<ENTITY> currentPaging = ever.getAuto(Controller.VIRTUAL_PAGING);
            mountPaging(currentPaging, config.getPageSize());
            this.paging = currentPaging;
            entities = currentPaging.getList();
            ever.put(vulpe.controller().selectPagingKey(), currentPaging);
        } else {
            onRead();
            manageVirtualPaging();
        }
        manageButtons();
        if (vulpe.controller().type().equals(ControllerType.SELECT)) {
            vulpe.view().targetName("entitySelect");
            if (vulpe.controller().back()) {
                controlResultForward();
                vulpe.controller().back(false);
            } else if (vulpe.controller().ajax() || vulpe.controller().exported()) {
                //vulpe.controller().resultForward(config.getViewItemsPath());
                vulpe.controller().resultForward(config.getAjaxViewPath());
            } else {
                controlResultForward();
            }
        } else if (vulpe.controller().type().equals(ControllerType.REPORT)) {
            vulpe.view().targetName("entitySelect");
            vulpe.controller().resultName(Result.REPORT);
            if (vulpe.controller().ajax()) {
                vulpe.controller().resultForward(config.getViewItemsPath());
            } else {
                controlResultForward();
            }
        } else if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.view().bodyTwice(ControllerType.SELECT);
            if (vulpe.controller().ajax()) {
                vulpe.controller().resultForward(config.getViewSelectItemsPath());
            } else {
                vulpe.controller().resultForward(config.getViewSelectPath());
            }
        } else {
            if (vulpe.controller().type().equals(ControllerType.TABULAR)) {
                if (VulpeValidationUtil.isNotEmpty(config.getDetails()) && VulpeValidationUtil.isEmpty(entities)
                        && !vulpe.controller().tabularFilter()) {
                    createDetails(config.getDetails(), false);
                } else if (VulpeValidationUtil.isEmpty(entities)) {
                    addActionInfoMessage(vulpe.controller().defaultMessage(Operation.READ));
                }
            }
            controlResultForward();
        }
        readAfter();
    }

    /**
     *
     */
    private void manageVirtualPaging() {
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (config.getControllerAnnotation().select().virtualPaging()) {
            final int size = VulpeValidationUtil.isNotEmpty(entities) ? entities.size() : 0;
            final Paging<ENTITY> paging = new Paging<ENTITY>(size, config.getPageSize(), 1);
            if (entities.size() > config.getPageSize()) {
                paging.setRealList(new ArrayList<ENTITY>(entities));
                int count = 1;
                for (final Iterator<ENTITY> iterator = entities.iterator(); iterator.hasNext();) {
                    iterator.next();
                    if (count > config.getPageSize()) {
                        iterator.remove();
                    }
                    ++count;
                }
            }
            paging.setList(entities);
            ever.putWeakRef(Controller.VIRTUAL_PAGING, paging);
            this.paging = paging;
        }
    }

    /**
     * Extension point to read record.
     *
     * @since 1.0
     */
    protected void onRead() {
        if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            if (ever.containsKey(vulpe.controller().selectFormKey()) && entitySelect == null) {
                entitySelect = ever.<ENTITY>getAuto(vulpe.controller().selectFormKey());
            }
            if (entitySelect == null) {
                entitySelect = entity;
            }
        }
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (config.requireOneOfFilters().length > 0 && isFiltersEmpty(entitySelect)) {
            final StringBuilder filters = new StringBuilder();
            final String orLabel = vulpe.controller().text("label.vulpe.or");
            int filterCount = 0;
            for (final String attribute : config.requireOneOfFilters()) {
                if (filterCount > 0) {
                    filters.append(" ").append(orLabel).append(" ");
                }
                final String text = config.getTitleKey() + "." + attribute;
                filters.append("\"").append(vulpe.controller().text(text)).append("\"");
                ++filterCount;
            }
            addActionError("{vulpe.error.validate.require.one.of.filters}", filters.toString());
            return;
        }
        final ENTITY entity = prepareEntity(Operation.READ);
        if (!vulpe.controller().exported()
                && ((vulpe.controller().type().equals(ControllerType.SELECT)
                        || vulpe.controller().type().equals(ControllerType.TWICE))
                        && (config.getPageSize() > 0 && !config.getControllerAnnotation().select().virtualPaging()))
                || (vulpe.controller().type().equals(ControllerType.TABULAR)
                        && vulpe.controller().config().getTabularPageSize() > 0)) {
            final Integer page = paging == null || paging.getPage() == null ? 1 : paging.getPage();
            vulpe.controller().currentPage(page);
            final Integer pageSize = vulpe.controller().type().equals(ControllerType.TABULAR)
                    ? vulpe.controller().config().getTabularPageSize()
                    : config.getPageSize();
            final Paging<ENTITY> currentPaging = (Paging<ENTITY>) invokeServices(
                    vulpe.serviceMethodName(Operation.PAGING),
                    new Class[] { config.getEntityClass(), Integer.class, Integer.class },
                    new Object[] { entity.clone(), pageSize, page });
            this.paging = currentPaging;
            entities = currentPaging.getList();
            ever.put(vulpe.controller().selectPagingKey(), currentPaging);
            if (vulpe.controller().type().equals(ControllerType.TABULAR)) {
                vulpe.controller().tabularSize(currentPaging.getSize());
                if (currentPaging.getList() == null || currentPaging.getList().isEmpty()) {
                    vulpe.controller().detail(Controller.ENTITIES);
                    if (!vulpe.controller().tabularFilter()) {
                        onAddDetail(true);
                    }
                }
            }
            if (VulpeValidationUtil.isEmpty(entities)) {
                addActionInfoMessage(vulpe.controller()
                        .defaultMessage(vulpe.controller().deleted() ? Operation.READ_DELETED : Operation.READ));
            }
        } else {
            final List<ENTITY> list = (List<ENTITY>) invokeServices(vulpe.serviceMethodName(Operation.READ),
                    new Class[] { config.getEntityClass() }, new Object[] { entity.clone() });
            entities = list;
            if (vulpe.controller().exported()) {
                initPaging();
            }
            if (config.getControllerAnnotation().select().virtualPaging()
                    && VulpeValidationUtil.isEmpty(entities)) {
                addActionInfoMessage(vulpe.controller()
                        .defaultMessage(vulpe.controller().deleted() ? Operation.READ_DELETED : Operation.READ));
            }
        }
        if (vulpe.controller().type().equals(ControllerType.REPORT)) {
            vulpe.controller().downloadInfo(doReportLoad());
            if (VulpeValidationUtil.isEmpty(entities)) {
                addActionInfoMessage(vulpe.controller().defaultMessage(Operation.REPORT_EMPTY));
            } else {
                addActionMessage(vulpe.controller().defaultMessage(Operation.REPORT_SUCCESS));
                initPaging();
            }
        } else {
            ever.put(vulpe.controller().selectFormKey(), entity.clone());
            if (entities != null && !entities.isEmpty()) {
                ever.put(vulpe.controller().selectTableKey(), entities);
            }
        }
        vulpe.controller().executed(true);
    }

    private void initPaging() {
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        final int size = VulpeValidationUtil.isNotEmpty(entities) ? entities.size() : 0;
        final Paging<ENTITY> currentPaging = new Paging<ENTITY>(size, config.getPageSize(), 1);
        currentPaging.setList(entities);
        paging = currentPaging;
    }

    /**
     * Extension point to code before read.
     *
     * @since 1.0
     */
    protected void readBefore() {
        if (!vulpe.controller().type().equals(ControllerType.SELECT)
                && !vulpe.controller().type().equals(ControllerType.TWICE)
                && !vulpe.controller().type().equals(ControllerType.TABULAR)
                && !vulpe.controller().type().equals(ControllerType.REPORT)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after read.
     *
     * @since
     */
    protected void readAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#tabularFilter()
     */
    public void tabularFilter() {
        vulpe.controller().tabularFilter(true);
        read();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#tabularPost()
     */
    public void tabularPost() {
        if (entities != null) {
            vulpe.controller().operation(Operation.TABULAR_POST);
            tabularPostBefore();
            controlResultForward();
            manageButtons();
            if (validateDetails() && onTabularPost()) {
                addActionMessage(vulpe.controller().defaultMessage());
                if (!entities.isEmpty()) {
                    final ENTITY entityTabular = entities.get(0);
                    if (entityTabular.getClass().isAnnotationPresent(CachedClass.class)) {
                        final String entityName = entityTabular.getClass().getSimpleName();
                        final List<ENTITY> list = new ArrayList<ENTITY>();
                        for (final ENTITY entity : entities) {
                            if (validateCacheClass(entity)) {
                                list.add(entity);
                            }
                        }
                        Collections.sort(list);
                        vulpe.cache().classes().put(entityName, list);
                    }
                }
            }
        }
        tabularPostAfter();
    }

    /**
     * Extension point to logic tabulate.
     *
     * @since 1.0
     */
    protected boolean onTabularPost() {
        final int size = entities.size();
        final int sizeDespise = entities.size();
        if (vulpe.controller().config().getTabularPageSize() > 0) {
            vulpe.controller().tabularSize(vulpe.controller().tabularSize() - (size - sizeDespise));
        }
        if (!VulpeValidationUtil.isEmpty(entities)) {
            for (final ENTITY entity : entities) {
                vulpe.updateAuditInfo(entity);
            }
            final List<ENTITY> list = (List<ENTITY>) invokeServices(vulpe.serviceMethodName(Operation.PERSIST),
                    new Class[] { List.class }, new Object[] { entities });
            entities = list;
        }
        tabularPagingMount(false);
        vulpe.controller().executed(true);
        return true;
    }

    /**
     * Extension point to code before logic tabulate.
     *
     * @since 1.0
     */
    protected void tabularPostBefore() {
        if (!vulpe.controller().type().equals(ControllerType.TABULAR)) {
            throw new VulpeSystemException(Error.CONTROLLER);
        }
    }

    /**
     * Extension point to code after logic tabulate.
     *
     * @since 1.0
     */
    protected void tabularPostAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#prepare()
     */
    public void prepare() {
        prepareBefore();
        onPrepare();
        manageButtons(Operation.PREPARE);
        if (vulpe.controller().type().equals(ControllerType.SELECT)
                || vulpe.controller().type().equals(ControllerType.REPORT)) {
            if (vulpe.controller().back()) {
                entitySelect = ever.<ENTITY>getAuto(vulpe.controller().selectFormKey());
                entities = ever.<List<ENTITY>>getAuto(vulpe.controller().selectTableKey());
                read();
            } else {
                ever.remove(vulpe.controller().selectFormKey());
                ever.remove(vulpe.controller().selectTableKey());
            }
            controlResultForward();
        } else if (vulpe.controller().type().equals(ControllerType.TABULAR)) {
            read();
        } else if (vulpe.controller().type().equals(ControllerType.TWICE)) {
            vulpe.view().bodyTwice(ControllerType.SELECT);
            vulpe.controller().resultForward(Layout.PROTECTED_JSP_COMMONS.concat(Layout.BODY_JSP));
        } else {
            controlResultForward();
        }
        prepareAfter();
    }

    public void twice() {
        vulpe.controller().type(ControllerType.TWICE);
        prepareBefore();
        onPrepare();
        manageButtons(Operation.TWICE);
        controlResultForward();
        prepareAfter();
    }

    public void export() {
        vulpe.controller().type(ControllerType.SELECT);
        exportBefore();
        vulpe.view().onlyToSee(true);
        vulpe.controller().exported(true);
        onExport();
        // vulpe.controller().resultForward(vulpe.controller().config().getViewItemsPath());
        // vulpe.controller().resultName(Result.EXPORT);
        ever.put(Ever.EXPORT_CONTENT, "PDF");
        exportAfter();
    }

    protected void onExport() {
        read();
    }

    protected void exportBefore() {
        // extension point
    }

    protected void exportAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#select()
     */
    @Override
    public void select() {
        vulpe.controller().type(ControllerType.SELECT);
        vulpe.view().targetName("entitySelect");
        selectBefore();
        onPrepare();
        manageButtons(Operation.PREPARE);
        if (vulpe.controller().back()) {
            entitySelect = ever.<ENTITY>getAuto(vulpe.controller().selectFormKey());
            entities = ever.<List<ENTITY>>getAuto(vulpe.controller().selectTableKey());
            paging = ever.<Paging<ENTITY>>getAuto(vulpe.controller().selectPagingKey());
            if (paging != null) {
                paging.setList(entities);
            }
        }
        controlResultForward();
        if (vulpe.controller().back()) {
            selectAfter();
            read();
            return;
        } else {
            ever.remove(vulpe.controller().selectFormKey());
            ever.remove(vulpe.controller().selectTableKey());
            ever.remove(vulpe.controller().selectPagingKey());
        }
        selectAfter();
        ever.remove(Controller.VIRTUAL_PAGING);
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if ((config.getControllerAnnotation().select().readOnShow()
                || (!config.getControllerAnnotation().disableApplicationDefaults()
                        && VulpeConfigHelper.getApplicationConfiguration().view().readOnShow()))
                && !vulpe.controller().cleaned()) {
            onRead();
            manageVirtualPaging();
        }
    }

    /**
     * Extension point to code before select.
     */
    protected void selectBefore() {
        // extension point
    }

    /**
     * Extension point to code after select.
     */
    protected void selectAfter() {
        // extension point
    }

    public void report() {
        vulpe.controller().type(ControllerType.REPORT);
        reportBefore();
        manageButtons(Operation.PREPARE);
        read();
        reportAfter();
        vulpe.controller().type(ControllerType.SELECT);
    }

    /**
     * Extension point to code before report.
     */
    protected void reportBefore() {
        // extension point
    }

    /**
     * Extension point to code after report.
     */
    protected void reportAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeController#tabular()
     */
    public void tabular() {
        vulpe.controller().type(ControllerType.TABULAR);
        final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
        if (config.isTabularShowFilter()) {
            try {
                entitySelect = config.getEntityClass().newInstance();
            } catch (Exception e) {
                LOG.error(e.getMessage());
            }
        }
        tabularBefore();
        onPrepare();
        manageButtons(Operation.TABULAR);
        tabularAfter();
        read();
    }

    /**
     * Extension point to code before tabular.
     */
    protected void tabularBefore() {
        // extension point
    }

    /**
     * Extension point to code after tabular.
     */
    protected void tabularAfter() {
        // extension point
    }

    /**
     * Extension point to prepare show.
     *
     * @since 1.0
     */
    protected void onPrepare() {
        entities = null;
        try {
            final VulpeBaseControllerConfig<ENTITY, ID> config = vulpe.controller().config();
            if (vulpe.controller().type().equals(ControllerType.TWICE) && entity == null) {
                entity = config.getEntityClass().newInstance();
            }
            if (entitySelect == null) {
                entitySelect = config.getEntityClass().newInstance();
            }
        } catch (Exception e) {
            if (vulpe.controller().type().equals(ControllerType.TWICE)) {
                entity = null;
            }
            entitySelect = null;
        }
        paging = null;
        vulpe.controller().executed(false);
    }

    /**
     * Extension point to code before prepare.
     */
    protected void prepareBefore() {
        // extension point
    }

    /**
     * Extension point to code after prepare.
     */
    protected void prepareAfter() {
        // extension point
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeSimpleController#upload()
     */
    public void upload() {
        uploadBefore();
        onUpload();
        uploadAfter();
        vulpe.controller().renderBoolean(vulpe.controller().uploaded());
    }

    /**
     * Extension point to upload.
     *
     * @since 1.0
     */
    protected void onUpload() {
        vulpe.controller().uploaded(true);
    }

    /**
     * Extension point to code before upload.
     *
     * @since 1.0
     */
    protected void uploadAfter() {
        LOG.debug("uploadAfter");
    }

    /**
     * Extension point to code after upload.
     *
     * @since 1.0
     */
    protected void uploadBefore() {
        LOG.debug("uploadBefore");
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeSimpleController#download()
     */
    public void download() {
        downloadBefore();
        onDownload();
        downloadAfter();
        vulpe.controller().resultName(Result.DOWNLOAD);
    }

    /**
     * Extension point to download.
     *
     * @since 1.0
     */
    protected void onDownload() {
        final DownloadInfo downloadInfo = prepareDownloadInfo();
        vulpe.controller().downloadInfo(downloadInfo);
    }

    /**
     * Extension point to prepare download.
     *
     * @since 1.0
     */
    protected abstract DownloadInfo prepareDownloadInfo();

    /**
     * Extension point to code before download.
     *
     * @since 1.0
     */
    protected void downloadAfter() {
        LOG.debug("downloadAfter");
    }

    /**
     * Extension point to code after download.
     *
     * @since 1.0
     */
    protected void downloadBefore() {
        LOG.debug("downloadBefore");
    }

    /**
     *
     * @param entity
     */
    public boolean isFiltersEmpty(final ENTITY entity) {
        boolean empty = true;
        for (String attribute : vulpe.controller().config().requireOneOfFilters()) {
            try {
                final Object value = PropertyUtils.getProperty(entity, attribute);
                if (VulpeValidationUtil.isNotEmpty(value)) {
                    empty = false;
                }
            } catch (Exception e) {
                LOG.debug(e.getMessage());
            }
        }
        return empty;
    }

    /**
     * Method to repair cached classes used by entity.
     *
     * @param entity
     * @return Entity with cached values reloaded
     */
    protected ENTITY repairCachedClasses(final ENTITY entity) {
        final List<Field> fields = VulpeReflectUtil.getFields(entity.getClass());
        for (final Field field : fields) {
            if (VulpeEntity.class.isAssignableFrom(field.getType())) {
                try {
                    final VulpeEntity<ID> value = (VulpeEntity<ID>) PropertyUtils.getProperty(entity,
                            field.getName());
                    if (VulpeValidationUtil.isNotEmpty(value) && !Modifier.isTransient(field.getModifiers())
                            && value.getClass().isAnnotationPresent(CachedClass.class)) {
                        final List<ENTITY> cachedList = vulpe.cache().classes()
                                .getAuto(value.getClass().getSimpleName());
                        if (VulpeValidationUtil.isNotEmpty(cachedList)) {
                            for (final ENTITY cached : cachedList) {
                                if (cached.getId().equals(value.getId())) {
                                    PropertyUtils.setProperty(entity, field.getName(), cached);
                                    break;
                                }
                            }
                        }
                    }
                } catch (IllegalAccessException e) {
                    LOG.error(e.getMessage());
                } catch (InvocationTargetException e) {
                    LOG.error(e.getMessage());
                } catch (NoSuchMethodException e) {
                    LOG.error(e.getMessage());
                }
            }
        }
        return entity;
    }

    /**
     *
     * @param entity
     * @return
     */
    private boolean validateCacheClass(final ENTITY entity) {
        boolean valid = true;
        final CachedClass cachedClass = vulpe.controller().config().getEntityClass()
                .getAnnotation(CachedClass.class);
        if (cachedClass != null && cachedClass.parameters().length > 0) {
            for (final QueryParameter queryParameter : cachedClass.parameters()) {
                if (StringUtils.isNotBlank(queryParameter.equals().name())
                        && StringUtils.isNotBlank(queryParameter.equals().value())) {
                    final Object value = VulpeReflectUtil.getFieldValue(entity, queryParameter.equals().name());
                    if (VulpeValidationUtil.isNotEmpty(value)
                            && !value.toString().equals(queryParameter.equals().value())) {
                        valid = false;
                        break;
                    }
                }
            }
        }
        return valid;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeSimpleController#backend()
     */
    public void backend() {
        vulpe.controller().config().setControllerType(ControllerType.BACKEND);
        vulpe.view().currentLayout("BACKEND");
        backendBefore();
        onBackend();
        controlResultForward();
        backendAfter();
    }

    /**
     * Extension point to prepare show.
     *
     * @since 1.0
     */
    protected void onBackend() {
        vulpe.controller().executed(false);
    }

    /**
     * Extension point to code before prepare.
     */
    protected void backendBefore() {
        LOG.debug("backendBefore");
    }

    /**
     * Extension point to code after prepare.
     */
    protected void backendAfter() {
        LOG.debug("backendAfter");
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeSimpleController#frontend()
     */
    public void frontend() {
        vulpe.controller().config().setControllerType(ControllerType.FRONTEND);
        vulpe.view().currentLayout("FRONTEND");
        frontendBefore();
        onFrontend();
        controlResultForward();
        frontendAfter();
    }

    /**
     * Extension point to prepare show.
     *
     * @since 1.0
     */
    protected void onFrontend() {
        vulpe.controller().executed(false);
    }

    /**
     * Extension point to code before prepare.
     */
    protected void frontendBefore() {
        LOG.debug("frontendBefore");
    }

    /**
     * Extension point to code after prepare.
     */
    protected void frontendAfter() {
        LOG.debug("frontendAfter");
    }

    public void none() {
        vulpe.controller().config().setControllerType(ControllerType.NONE);
        controlResultForward();
        vulpe.controller().executed(false);
    }

    /**
     * Method to invoke services.
     *
     * @param serviceName
     *            Name of service
     * @param argsType
     *            Types of arguments
     * @param argsValues
     *            Arguments values
     *
     * @since 1.0
     * @return Object
     */
    public Object invokeServices(final String serviceName, final Class<?>[] argsType, final Object[] argsValues) {
        final VulpeService service = vulpe.service();
        try {
            final Method method = service.getClass().getMethod(serviceName, argsType);
            return method.invoke(service, argsValues);
        } catch (Exception e) {
            throw new VulpeSystemException(e);
        }
    }

    /**
     * Method to add error message.
     *
     * @param key
     *            Key in resource bundle
     * @param args
     *            arguments
     *
     * @since 1.0
     */
    public void addActionError(final String key, final Object... args) {
        addActionError(vulpe.controller().text(key, args));
    }

    /**
     * Method to add error message.
     *
     * @param key
     *            Key in resource bundle
     *
     * @since 1.0
     */
    public void addActionErrorKey(final String key) {
        addActionError(vulpe.controller().text(key));
    }

    /**
     * Method to add warning message.
     *
     * @param key
     *            Key in resource bundle
     * @param args
     *            arguments
     *
     * @since 1.0
     */
    public void addActionMessage(final String key, final Object... args) {
        addActionMessage(vulpe.controller().text(key, args));
    }

    public void addActionInfoMessage(final String key, final Object... args) {
        addActionInfoMessage(vulpe.controller().text(key, args));
    }

    public void addActionInfoMessage(final String aMessage) {
        if (StringUtils.isNotBlank(aMessage)) {
            if (aMessage.startsWith("{") && aMessage.endsWith("}")) {
                final String message = vulpe.controller().text(aMessage.substring(1, aMessage.length() - 1));
                actionInfoMessages.add(message);
            } else {
                actionInfoMessages.add(aMessage);
            }
        }
    }

    /**
     * Method to add warning message.
     *
     * @param key
     *            Key in resource bundle
     *
     * @since 1.0
     */
    public void addActionMessageKey(final String key) {
        addActionMessage(vulpe.controller().text(key));
    }

    /*
     * (non-Javadoc)
     *
     * @see org.vulpe.controller.VulpeSimpleController#controlResultForward()
     */
    public void controlResultForward() {
        vulpe.controller()
                .resultForward(vulpe.controller().type().equals(ControllerType.TWICE)
                        ? Layout.PROTECTED_JSP_COMMONS.concat(Layout.BODY_TWICE_JSP)
                        : Layout.PROTECTED_JSP_COMMONS.concat(Layout.BODY_JSP));
    }

    public abstract void addActionMessage(final String message);

    public abstract void addActionError(final String message);

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}