All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tools.dynamia.zk.crud.CrudController Maven / Gradle / Ivy

There is a newer version: 5.2.1
Show newest version
/*
 * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1
 * Colombia / South America
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package tools.dynamia.zk.crud;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.WrongValuesException;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;
import org.zkoss.zul.ext.Paginal;
import tools.dynamia.commons.BeanMap;
import tools.dynamia.commons.BeanSorter;
import tools.dynamia.commons.BeanUtils;
import tools.dynamia.commons.Callback;
import tools.dynamia.commons.StringUtils;
import tools.dynamia.commons.logger.LoggingService;
import tools.dynamia.commons.logger.SLF4JLoggingService;
import tools.dynamia.crud.CrudControllerAPI;
import tools.dynamia.domain.CrudServiceException;
import tools.dynamia.domain.ValidationError;
import tools.dynamia.domain.jdbc.QueryInterruptedException;
import tools.dynamia.domain.query.DataPaginator;
import tools.dynamia.domain.query.DataSet;
import tools.dynamia.domain.query.ListDataSet;
import tools.dynamia.domain.query.QueryExecuter;
import tools.dynamia.domain.query.QueryParameters;
import tools.dynamia.domain.services.CrudService;
import tools.dynamia.domain.util.DomainUtils;
import tools.dynamia.domain.util.QueryBuilder;
import tools.dynamia.integration.Containers;
import tools.dynamia.ui.MessageType;
import tools.dynamia.ui.UIMessages;
import tools.dynamia.viewers.DataSetView;
import tools.dynamia.viewers.Field;
import tools.dynamia.viewers.util.Viewers;
import tools.dynamia.zk.util.ZKUtil;
import tools.dynamia.zk.viewers.table.TableView;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * This class works as crud controllers for ZK web applications
 *
 * @author Ing. Mario Serrano Leones
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public class CrudController extends SelectorComposer implements Serializable, CrudControllerAPI {

    /**
     *
     */
    private static final long serialVersionUID = 5762960709271600367L;
    private E entity;
    private E example;
    private E selected;
    private DataSet queryResult;
    private QueryParameters params;
    private Class entityClass;
    protected LoggingService logger;
    protected CrudService crudService;
    private boolean autoClearPage = false;
    private boolean autoReloadEntity = true;
    private final List subcontrollers = new ArrayList<>();
    // util
    private String name;
    private Window currentDialog;
    private final BeanSorter sorter = new BeanSorter();
    private DataPaginator dataPaginator;
    // auto wired zk components
    private Paginal paginator;
    protected DataSetView dataSetView;
    private boolean alwaysFindByExample = false;
    private boolean saved;
    private boolean deleted;
    private final Map defaultEntityValues = new HashMap<>();
    private boolean confirmBeforeSave;
    private Callback onSaveCallback;
    private boolean queryProjection;
    private QueryParameters defaultParameters;
    private Map attributes = new HashMap<>();
    private boolean saveWithNewTransaction = true;


    public CrudController() {
        this(null);
    }

    public CrudController(Class entityClass) {
        this.entityClass = entityClass;
        init();
    }

    public CrudController(Class entityClass, CrudService crudService) {
        this.entityClass = entityClass;
        this.crudService = crudService;
        init();
    }

    public void addSubcrudController(SubcrudController subController) {
        subController.setParentEntity(getEntity());
        subcontrollers.add(subController);
    }

    @Override
    public boolean isConfirmBeforeSave() {
        return confirmBeforeSave;
    }

    @Override
    public void setConfirmBeforeSave(boolean confirmBeforeSave) {
        this.confirmBeforeSave = confirmBeforeSave;
    }

    protected List getSubcontrollers() {
        return subcontrollers;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#setCrudService(com.dynamia
     * .tools.domain.services.CrudService)
     */
    @Override
    public void setCrudService(CrudService crudService) {
        this.crudService = crudService;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getCrudService()
     */
    @Override
    public CrudService getCrudService() {
        return crudService;
    }

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);

        Object ent = getArg("entity");

        if (ent != null && ent.getClass().equals(entityClass)) {
            setEntity((E) ent);
            reloadEntity();
        }

        Object dialog = getArg("dialog");

        if (dialog != null && dialog instanceof Window) {
            this.currentDialog = (Window) dialog;
        }

        afterPageLoaded();
    }


    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#save()
     */
    @Override
    public void save() {
        logger.debug("Saving entity " + entityClass);
        if (isSaveWithNewTransaction()) {
            crudService.executeWithinTransaction(() -> crudService.save(entity, DomainUtils.findEntityId(entity)));
        } else {
            crudService.save(entity, DomainUtils.findEntityId(entity));
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#delete()
     */
    @Override
    public void delete() {
        if (DomainUtils.isEntity(getSelected())) {
            crudService.delete(getSelected().getClass(), DomainUtils.findEntityId(getSelected()));
        } else {
            crudService.delete(getSelected());
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#query()
     */
    @Override
    public void query() {

        try {
            if (BeanUtils.isAssignable(entityClass, QueryExecuter.class)) {
                QueryExecuter queryExecutor = (QueryExecuter) BeanUtils.newInstance(entityClass);
                setQueryResult(new ListDataSet(queryExecutor.executeQuery(crudService, getParams())));
            } else if (alwaysFindByExample) {
                setQueryResult(new ListDataSet(crudService.findByExample(getExample(), getParams())));
            } else if (queryProjection) {
                setQueryResult(new ListDataSet(crudService.executeQuery(createQueryProjection(), getParams())));
            } else {
                setQueryResult(new ListDataSet(crudService.find(entityClass, getParams())));
            }

        } catch (CrudServiceException e) {
            if (getQueryResult() == null || getQueryResult().getSize() <= 0) {
                UIMessages.showMessage("La consulta no arrojo resultados");
            }
        } catch (QueryInterruptedException e) {
            logger.error(e);
            Messagebox.show("La consulta demora mucho tiempo en procesarse, por favor utilice otros filtros" +
                            " o intente mas tarde. Por ejemplo, si esta usando un rango de fechas reduzca la diferencia. ", "Error al Consultar",
                    Messagebox.OK, Messagebox.ERROR);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e);
            UIMessages.showMessage("Error al consultar: " + e.getMessage(), MessageType.ERROR);
        }
    }

    private QueryBuilder createQueryProjection() {
        List fields = Viewers.getFields(dataSetView.getViewDescriptor()).stream().map(Field::getName).collect(Collectors.toList());
        fields = new ArrayList<>(fields);
        fields.add(0, "id");
        return QueryBuilder.select(fields.toArray(new String[0])).from(entityClass, "e").where(getParams())
                .resultType(BeanMap.class);
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#delete(E)
     */
    @Override
    public final void delete(E entity) {
        setSelected(entity);
        doDelete();
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#edit(E)
     */
    @Override
    public final void edit(E entity) {
        setSelected(entity);
        doEdit();
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#newEntity()
     */
    @Override
    public void newEntity() {
        if (entityClass != null) {
            try {
                entity = BeanUtils.newInstance(entityClass);
                BeanUtils.setupBean(entity, getDefaultEntityValues());
            } catch (Exception ex) {
                logger.error("Error creating new entity", ex);
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#newExample()
     */
    @Override
    public void newExample() {
        if (entityClass != null) {
            try {
                example = BeanUtils.newInstance(entityClass);
            } catch (Exception ex) {
                logger.error("Error creating new example object", ex);
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#reloadEntity()
     */
    @Override
    public void reloadEntity() {
        if (entity != null && DomainUtils.findEntityId(entity) != null && autoReloadEntity) {
            entity = crudService.findSingle(entityClass, "id", DomainUtils.findEntityId(entity));
            autoReloadEntity = true;
        }
    }

    public void closeCurrentDialog() {
        if (currentDialog != null) {
            Events.postEvent(Events.ON_CLOSE, currentDialog, this);
            currentDialog.detach();
            currentDialog.setVisible(false);
            currentDialog = null;
        }
    }

    protected void exceptionCaught(Exception e) {
        if (e instanceof ValidationError) {
            UIMessages.showMessage(e.getMessage(), MessageType.ERROR);
            throw (ValidationError) e;

        } else {
            logger.error(e);

        }
    }

    // 
    protected void afterPageLoaded() {
    }

    protected void beforeCreate() {
    }

    protected void afterCreate() {
    }

    protected void beforeSave() {
    }

    protected void afterSave() {
    }

    protected void beforeQuery() {
    }

    protected void afterQuery() {
    }

    protected void beforeEdit() {
    }

    protected void afterEdit() {
    }

    protected void beforeDelete() {
    }

    protected void afterDelete() {
    }// 

    // 
    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getEntity()
     */
    @Override
    public E getEntity() {
        if (entity == null) {
            newEntity();
        }
        return entity;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#setEntity(E)
     */
    @Override
    public void setEntity(E entity) {
        this.entity = entity;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getExample()
     */
    @Override
    public E getExample() {
        if (example == null) {
            newExample();
        }
        return example;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getSelected()
     */
    @Override
    public E getSelected() {
        return selected;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#isSaved()
     */
    @Override
    public boolean isSaved() {
        return saved;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#isDeleted()
     */
    @Override
    public boolean isDeleted() {
        return deleted;
    }

    public void setAlwaysFindByExample(boolean alwaysFindByExample) {
        this.alwaysFindByExample = alwaysFindByExample;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#setSelected(E)
     */
    @Override
    public void setSelected(E selected) {
        this.selected = selected;
        if (dataSetView != null) {
            dataSetView.setSelected(selected);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getParams()
     */
    @Override
    public QueryParameters getParams() {
        return params;
    }


    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#setParams(com.dynamia.tools
     * .domain.query.QueryParameters)
     */
    @Override
    public void setParams(QueryParameters params) {
        this.params = params;
        if (this.getParams() == null) {
            this.params = new QueryParameters();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.dynamia.tools.web.crud.ICrudController#getParameter(java.lang.String)
     */
    @Override
    public Object getParameter(String param) {
        return getParams().get(param);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.dynamia.tools.web.crud.ICrudController#setParemeter(java.lang.String,
     * java.lang.Object)
     */
    @Override
    public void setParemeter(String key, Object value) {
        if (value != null) {
            params.put(key, value);
        } else {
            params.remove(key);
        }
    }

    @Override
    public DataSet getQueryResult() {
        return queryResult;
    }

    public List getQueryResultList() {
        if (queryResult instanceof ListDataSet) {
            return ((ListDataSet) queryResult).getData();
        } else {
            return Collections.emptyList();
        }
    }

    @Override
    public void setQueryResult(DataSet queryResult) {
        this.queryResult = queryResult;
        updateDataSetView();
        afterQuery();

        if (isQueryResultEmpty() && dataSetView.isEmpty()) {
            UIMessages.showMessage("La consulta no arrojo resultados", MessageType.WARNING);
        }
    }

    /**
     * Set result list
     */
    public final void setQueryResult(List queryResult) {
        setQueryResult(new ListDataSet(queryResult));
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#isQueryResultEmpty()
     */
    @Override
    public boolean isQueryResultEmpty() {
        if (getQueryResult() == null) {
            return true;
        }
        return getQueryResult().getSize() == 0;
    }

    public boolean isAutoClearPage() {
        return autoClearPage;
    }

    public void setAutoClearPage(boolean autoClearPage) {
        this.autoClearPage = autoClearPage;
    }

    public void setPaginator(Paginal paginator) {
        this.paginator = paginator;
    }

    public void setDataSetView(DataSetView dataSetView) {
        this.dataSetView = dataSetView;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getDataPaginator()
     */
    @Override
    public DataPaginator getDataPaginator() {
        return dataPaginator;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getSorter()
     */
    @Override
    public BeanSorter getSorter() {
        return sorter;
    }

    public Window getCurrentDialog() {
        return currentDialog;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#getEntityClass()
     */
    @Override
    public Class getEntityClass() {
        return entityClass;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.dynamia.tools.web.crud.ICrudController#setEntityClass(java.lang.Class )
     */
    @Override
    public void setEntityClass(Class entityClass) {
        this.entityClass = entityClass;
        if (entityClass != null) {
            name = StringUtils.addSpaceBetweenWords(entityClass.getSimpleName());
        }
    }// 

    // 
    private void init() {
        if (crudService == null) {
            crudService = Containers.get().findObject(CrudService.class);
        }

        if (logger == null) {
            logger = Containers.get().findObject(LoggingService.class);
        }

        if (logger == null) {
            logger = new SLF4JLoggingService(CrudController.class);
        }

        params = new QueryParameters();
        if (entityClass == null) {
            try {
                setEntityClass(BeanUtils.getGenericTypeClass(this));

            } catch (Exception e) {
                logger.warn(
                        "Cannot get generic class for EntityClass, you should invoke setEntityClass or use the constructor");
            }
        }

        newEntity();
        afterInit();
    }

    protected void updateDataSetView() {
        if (dataSetView != null) {
            dataSetView.setValue(getQueryResult());
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#doQuery()
     */
    @Override
    public final void doQuery() {
        try {
            if (defaultParameters != null && !defaultParameters.isEmpty()) {
                defaultParameters.forEach(this::setParemeter);
            }
            configurePaginator();
            configureSorter();
            beforeQuery();
            query();

        } catch (Exception e) {
            exceptionCaught(e);
        }
    }

    private void configurePaginator() {
        if (paginator != null) {
            dataPaginator = new DataPaginator();
            dataPaginator.setPageSize(paginator.getPageSize());
            getParams().paginate(dataPaginator);

            if (dataSetView.getViewDescriptor().getParams().get("pagination") == Boolean.FALSE) {
                getParams().paginate(null);
            }
        }
    }

    private void configureSorter() {
        if (getParams().getSorter() == null) {
            getParams().sort(sorter);

            if (dataSetView instanceof TableView tableView) {
                if (tableView.getOrderBy() != null) {
                    getParams().orderBy(tableView.getOrderBy(), true);
                }
                if (tableView.getMaxResults() > 0) {
                    getParams().setMaxResults(tableView.getMaxResults());
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#doSave()
     */
    @Override
    @Listen("onClick = #save")
    public final void doSave() {
        Callback saveCallbak = () -> {
            saved = false;
            try {
                doDeletesInSubcontrollers();
                beforeSave();
                save();
                doChangesInSubcontrollers();
                showMessageOnSaveSuccessfull();
                saved = true;
                afterSave();
                newEntity();
                closeCurrentDialog();
                if (isAutoClearPage()) {
                    ZKUtil.clearPage(getPage());
                }
                if (onSaveCallback != null) {
                    onSaveCallback.doSomething();
                }
            } catch (WrongValueException | WrongValuesException e) {
                throw e;
            } catch (Exception e) {
                logger.error("Error al guardar " + entityClass, e);
                exceptionCaught(e);
            }
        };

        if (isConfirmBeforeSave()) {
            UIMessages.showQuestion("¿Esta seguro que desea guardar " + name + "?", saveCallbak);
        } else {
            saveCallbak.doSomething();
        }
    }

    @Override
    public void onSave(Callback onSave) {
        this.onSaveCallback = onSave;

    }

    public void showMessageOnSaveSuccessfull() {
        if (name != null) {
            UIMessages.showMessage(name + " guardado correctamente ");
        } else {
            UIMessages.showMessage(getEntity() + " guardado correctamente ");
        }
    }

    protected void doDeletesInSubcontrollers() {
        if (!(this instanceof SubcrudController)) {
            if (!subcontrollers.isEmpty()) {
                for (SubcrudController subcontroller : subcontrollers) {
                    try {
                        subcontroller.doDeletes();
                    } catch (Exception e) {
                        logger.warn("Exception running subcrud controller " + subcontroller + ": " + e.getMessage());
                    }
                }
            }
        }
    }

    protected void doChangesInSubcontrollers() {
        if (!(this instanceof SubcrudController)) { // Parent controllers

            if (!subcontrollers.isEmpty()) {
                for (SubcrudController subcontroller : subcontrollers) {
                    try {
                        subcontroller.doCreates();
                        subcontroller.doUpdates();
                    } catch (Exception e) {
                        logger.warn("Exception running subcrud controller " + subcontroller + ": " + e.getMessage());
                    }
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#doSaveAndEdit()
     */
    @Override
    public final void doSaveAndEdit() {
        saved = false;
        try {
            beforeSave();
            save();
            UIMessages.showMessage(name + " guardado correctamente, puede continuar editando el registro ");
            afterSave();
            setSelected(getEntity());
            doEdit();
            saved = true;
        } catch (WrongValueException | WrongValuesException e) {
            throw e;
        } catch (Exception e) {
            logger.error("Error al guardar " + entityClass, e);
            exceptionCaught(e);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#doEdit()
     */
    @Override
    @Listen("onClick = #edit")
    public final void doEdit() {
        saved = true;
        Object ent = getSelected();
        if (ent != null) {
            beforeEdit();
            var entityId = DomainUtils.findEntityId(ent);
            if (entityId != null) {
                setEntity(crudService.find(entityClass, entityId));
            } else {
                setEntity((E) ent);
            }
            afterEdit();
        } else {
            UIMessages.showMessage("Seleccione " + name + " para editar", MessageType.WARNING);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#doDelete()
     */
    @Override
    @Listen("onClick = #delete")
    public final void doDelete() {

        deleted = false;
        if (getSelected() != null) {
            beforeDelete();
            UIMessages.showQuestion(
                    "¿Esta seguro que desea borrar: " + name + "  " + getSelected().toString() + "?", () -> {
                        try {
                            delete();

                            afterDelete();
                            doQuery();
                            deleted = true;
                            UIMessages.showMessage(getSelected() + " borrado exitosamente");
                            setSelected(null);
                        } catch (ValidationError e) {
                            UIMessages.showMessage(e.getMessage(), MessageType.WARNING);
                        } catch (Exception e) {
                            logger.error(e);
                            if (e.getMessage() != null && e.getMessage().contains("ConstraintViolationException")) {
                                UIMessages.showMessage("No se puede eliminar " + name + " porque esta siendo usado o tiene registros asociados",
                                        MessageType.WARNING);
                            } else {
                                UIMessages.showMessage("Error al eliminar " + name + " contacte al administrador del sistema",
                                        MessageType.ERROR);

                            }

                        }
                    });
        } else {
            UIMessages.showMessage("Seleccione " + name + " para borrar", MessageType.WARNING);
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see com.dynamia.tools.web.crud.ICrudController#doCreate()
     */
    @Override
    @Listen("onClick = #create")
    public final void doCreate() {
        saved = false;
        beforeCreate();
        newEntity();
        afterCreate();
    }

    // 
    @Override
    public Map getDefaultEntityValues() {
        return defaultEntityValues;
    }

    public Object getArg(Object name) {

        return Executions.getCurrent().getArg().get(name);
    }

    protected void afterInit() {
    }


    @Override
    public void clear() {
        queryResult = null;
        params = new QueryParameters();
    }

    protected void log(String message) {
        logger.info(message);
    }

    protected void log(String messsage, Throwable exception) {
        logger.error(messsage, exception);
    }

    public boolean isQueryProjection() {
        return queryProjection;
    }

    public void setQueryProjection(boolean queryProjection) {
        this.queryProjection = queryProjection;
    }

    public QueryParameters getDefaultParameters() {
        return defaultParameters;
    }

    public void setDefaultParameters(QueryParameters defaultParameters) {
        this.defaultParameters = defaultParameters;
    }

    public Map getAttributes() {
        return attributes;
    }

    public void setAttributes(Map attributes) {
        this.attributes = attributes;
    }

    public boolean isSaveWithNewTransaction() {
        return saveWithNewTransaction;
    }

    public void setSaveWithNewTransaction(boolean saveWithNewTransaction) {
        this.saveWithNewTransaction = saveWithNewTransaction;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy