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

org.javabeanstack.services.AbstractDataService Maven / Gradle / Ivy

The newest version!
/*
* JavaBeanStack FrameWork
*
* Copyright (C) 2017 Jorge Enciso
* Email: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301  USA
 */
package org.javabeanstack.services;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.JoinColumn;
import org.apache.log4j.Logger;
import org.javabeanstack.error.ErrorManager;
import org.javabeanstack.error.IErrorReg;
import org.javabeanstack.exceptions.SessionError;
import org.javabeanstack.security.IUserSession;
import org.javabeanstack.data.DataInfo;
import org.javabeanstack.data.DataResult;
import org.javabeanstack.data.IDataResult;
import org.javabeanstack.data.IDataRow;
import org.javabeanstack.annotation.CheckMethod;
import org.javabeanstack.data.AbstractDAO;
import org.javabeanstack.data.DBLinkInfo;
import org.javabeanstack.data.IDBLinkInfo;
import org.javabeanstack.error.ErrorReg;
import org.javabeanstack.util.Fn;

/**
 * Esta clase deriva de AbstractDAO, a travéz de ella se recupera, válida y se
 * graban los registros en la base de datos. Es un ejb que se ejecuta en la capa
 * de la lógica del negocio.
 *
 * El test unitario se encuentra en TestProjects clase
 * py.com.oym.test.data.TestDataService
 *
 * @author Jorge Enciso
 */
public abstract class AbstractDataService extends AbstractDAO implements IDataService {

    private static final Logger LOGGER = Logger.getLogger(AbstractDataService.class);
    protected List methodList = this.setListCheckMethods();

    /**
     * Genera una lista de los metodos que existen con el proposito de validar
     * datos.
     *
     * @return lista de metodos.
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    protected final List setListCheckMethods() {
        List methods = new ArrayList();
        for (Method method : this.getClass().getDeclaredMethods()) {
            String namePrefix = method.getName().toLowerCase().substring(0, 5);
            CheckMethod anotation = method.getAnnotation(CheckMethod.class);
            /* Ejecutar los metodos cuyo nombre inician con check */
            if ("check".equals(namePrefix) || anotation != null) {
                methods.add(method);
            }
        }
        return methods;
    }

    // TODO ver este metodo.
    @Override
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public  T setListFieldCheck(T row) {
        if (row != null && row.getFieldChecked() == null) {
            String fieldName;
            String key;
            String namePrefix;
            CheckMethod anotation;
            Map fieldChecked = new HashMap<>();
            for (Method method : this.getClass().getDeclaredMethods()) {
                namePrefix = method.getName().toLowerCase().substring(0, 5);
                anotation = method.getAnnotation(CheckMethod.class);
                if ("check".equals(namePrefix) || anotation != null) {
                    if (anotation == null) {
                        fieldName = method.getName().toLowerCase().substring(5);
                    } else {
                        fieldName = anotation.fieldName().toLowerCase();
                    }
                    key = "_" + fieldName;
                    fieldChecked.put(key, true);
                }
            }
            row.setFieldChecked(fieldChecked);
        }
        return row;
    }

    /**
     * Válida que la clave del registro no exista en la tabla.
     *
     * @param 
     * @param row registro con los datos.
     * @param sessionId identificador de la sesión que permite realizar las
     * operaciones sobre la base de datos.
     * @return verdadero si no esta duplicado y falso si lo esta.
     */
    @Override
    public  boolean checkUniqueKey(T row, String sessionId) {
        try {
            // Buscar registro por la clave unica
            if (row.getQueryUK() == null) {
                return true;
            }
            T row2 = (T) findByUk(IDataRow.class, getDBLinkInfo(sessionId), row);
            // Si encontro un registro
            if (row2 != null) {
                // Y la operación es agregar 
                if (row.getAction() == IDataRow.INSERT) {
                    return false;
                }
                // Y no son el mismo objeto devolver error
                if (row.hashCode() != row2.hashCode()) {
                    return false;
                }
            }
        } catch (Exception ex) {
            ErrorManager.showError(ex, Logger.getLogger(AbstractDataService.class));
        }
        return true;
    }

    /**
     * Válida que los campos definidos como clave foranea existan en la tabla
     * relacionada o sea nulo si así lo permite el campo.
     *
     * @param 
     * @param row registro de datos.
     * @param fieldName nombre del campo
     * @param sessionId identificador de la sesión que permite realizar las
     * operaciones sobre la base de datos.
     * @return verdadero si no esta duplicado y falso si lo esta.
     */
    @Override
    public  boolean checkForeignKey(T row, String fieldName, String sessionId) {
        boolean result = true;
        try {
            Class clase = row.getClass();
            Field field = DataInfo.getDeclaredField(clase, fieldName);
            // Si el campo no existe
            if (field == null) {
                result = true;
            } // Si no es foreignkey
            else if (!DataInfo.isForeignKey(row.getClass(), fieldName)) {
                result = true;
            } else {
                Boolean nullable = field.getAnnotation(JoinColumn.class).nullable();
                // Si el valor es nulo y no se permite nulo
                if (row.getValue(fieldName) == null && !nullable) {
                    result = false;
                } // Buscar valor del foreignkey
                else if (row.getValue(fieldName) != null) {
                    Class fieldType = row.getFieldType(fieldName);
                    Object id = row.getValue(fieldName);
                    IDataRow fieldValue = find(fieldType, getDBLinkInfo(sessionId), id);
                    if (fieldValue == null) {
                        result = false;
                    }
                }
            }
        } catch (Exception exp) {
            result = false;
        }
        return result;
    }

    /**
     * Chequea la validez de los datos del registro, ejecutando todos los
     * metodos marcados como validadores (CheckMethod).
     *
     * @param 
     * @param row registro de datos.
     * @param sessionId identificador de la sesión que permite realizar las
     * operaciones sobre la base de datos.
     * @return un objeto map conteniendo el resultado de las validaciones de
     * todos los campos, en caso de existir algún error, existe su objeto de
     * error (IErrorReg) asociado a una clave que en este caso es el nombre del
     * campo.
     */
    @Override
    public  Map checkDataRow(T row, String sessionId) {
        Map errors = new HashMap<>();
        String fieldName;
        int[] operacion = {IDataRow.INSERT, IDataRow.UPDATE};
        IErrorReg result;
        CheckMethod anotation;
        try {
            // Chequeo de clave duplicada solo si la operación es agregar o modificar
            if (Fn.inList(row.getAction(), IDataRow.INSERT, IDataRow.UPDATE)) {
                if (!checkUniqueKey(row, sessionId)) {
                    errors.put("UNIQUEKEY",
                            new ErrorReg("Este registro ya existe",
                                    50001,
                                    DataInfo.getUniqueFields(row.getClass())));
                    return errors;
                }
            }
            // Ejecutar control de foreignkey
            // Chequeo del foreignkey solo si la operación es agregar o modificar
            if (Fn.inList(row.getAction(), IDataRow.INSERT, IDataRow.UPDATE)) {
                for (Field field : DataInfo.getDeclaredFields(row.getClass())) {
                    fieldName = field.getName();
                    if (!checkForeignKey(row, fieldName, sessionId)) {
                        errors.put(fieldName.toLowerCase(),
                                new ErrorReg("Dejo en blanco este dato o no existe el registro",
                                        50013,
                                        fieldName));
                    }
                }
            }
        } catch (Exception exp) {
            ErrorManager.showError(exp, LOGGER);
        }
        // Ejecutar metodos de chequeo de datos
        for (Method method : this.methodList) {
            anotation = method.getAnnotation(CheckMethod.class);
            if (anotation == null) {
                fieldName = method.getName().toLowerCase().substring(5);
            } else {
                fieldName = anotation.fieldName();
                operacion = anotation.action();
            }
            // Si existe un error previo sobre este campo continuar con las otras validaciones
            if (errors.containsKey(fieldName.toLowerCase())) {
                continue;
            }
            try {
                method.setAccessible(true);
                // La validación se ejecuta dependiendo de la operación (agregar, modificar, borrar)
                if (Fn.inList(row.getAction(), operacion)) {
                    result = (IErrorReg) method.invoke(this, row, sessionId);
                    if (result != null && !"".equals(result.getMessage())) {
                        errors.put(fieldName.toLowerCase(), result);
                    }
                }
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                ErrorManager.showError(ex, Logger.getLogger(AbstractDataService.class));
            }
        }
        row.setErrors(errors);
        row.setRowChecked(true);
        return errors;
    }

    /**
     * Verifica que sea valida la sesión de usuario para poder realizar las
     * operaciones.
     *
     * @param sessionId identificador de la sesión.
     * @throws SessionError error sesión invalida.
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    protected final void checkUserSession(String sessionId) throws SessionError {
        IUserSession userSession = getUserSession(sessionId);
        if (userSession == null || userSession.getUser() == null) {
            throw new SessionError("El identificador de la sesión es inválido");
        }
    }

    /**
     * Devuelve la unidad de persistencia asociado a la empresa en la cual
     * inicio sesión el usuario.
     *
     * @param sessionId identificador de la sesión.
     * @return unidad de persistencia.
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    protected String getPersistentUnit(String sessionId) {
        IUserSession userSession = getUserSession(sessionId);
        if (userSession == null || userSession.getUser() == null) {
            return null;
        }
        return userSession.getPersistenceUnit();
    }

    /**
     * Se ejecuta en el metodo save, valida los datos del registro
     * (checkDataRow) y devuelve el resultado en un objeto IDataResult
     *
     * @param 
     * @param row registro de datos.
     * @param sessionId identificador de la sesión.
     * @return objeto con el resultado del proceso de validación.
     */
    protected final  IDataResult checkDataResult(T row, String sessionId) {
        IDataResult dataResult = new DataResult();
        dataResult.setSuccess(Boolean.TRUE);
        List ejbsRes = new ArrayList();
        // Validar el registro
        Map errors = this.checkDataRow(row, sessionId);
        ejbsRes.add(row);
        if (!errors.isEmpty()) {
            // Devolver el error si lo hubo
            dataResult.setSuccess(Boolean.FALSE);
            dataResult.setErrorsMap(errors);
        }
        dataResult.put("1", ejbsRes);
        return dataResult;
    }

    /**
     * Graba un registro en la base de datos.
     *
     * @param 
     * @param row registro de datos.
     * @param sessionId identificador de la sesión.
     * @return objeto resultado de la operación.
     * @throws SessionError
     */
    protected final  IDataResult save(T row, String sessionId) throws SessionError {
        checkUserSession(sessionId);
        IDataResult dataResult;
        // Validar registro
        dataResult = this.checkDataResult(row, sessionId);
        if (!dataResult.getErrorsMap().isEmpty()) {
            // Devolver el error si lo hubo
            return dataResult;
        }
        // Grabar registro en la base de datos.
        dataResult = update(getDBLinkInfo(sessionId), row);
        return dataResult;
    }

    /**
     * Agrega un registro en la tabla
     *
     * @param 
     * @param row registro de datos.
     * @param sessionId identificador de la sesión.
     * @return objeto resultado de la operación.
     * @throws SessionError
     */
    @Override
    public  IDataResult create(T row, String sessionId) throws SessionError {
        row.setAction(IDataRow.INSERT);
        return save(row, sessionId);
    }

    /**
     * Modifica un registro en la tabla
     *
     * @param 
     * @param row registro de datos.
     * @param sessionId identificador de la sesión.
     * @return objeto resultado de la operación.
     * @throws org.javabeanstack.exceptions.SessionError
     */
    @Override
    public  IDataResult edit(T row, String sessionId) throws SessionError {
        row.setAction(IDataRow.UPDATE);
        return save(row, sessionId);
    }

    /**
     * Borra un registro en la tabla
     *
     * @param 
     * @param row registro de datos.
     * @param sessionId identificador de la sesión.
     * @return objeto resultado de la operación.
     * @throws org.javabeanstack.exceptions.SessionError
     */
    @Override
    public  IDataResult remove(T row, String sessionId) throws SessionError {
        row.setAction(IDataRow.DELETE);
        return save(row, sessionId);
    }

    private IDBLinkInfo getDBLinkInfo(String sessionId) {
        IDBLinkInfo dbInfo = new DBLinkInfo();
        dbInfo.setUserSession(getUserSession(sessionId));
        return dbInfo;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy