Package org.paquitosoft.lml.model.util

Source Code of org.paquitosoft.lml.model.util.ModelUtilities

package org.paquitosoft.lml.model.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.paquitosoft.lml.model.annotation.AssociationType;
import org.paquitosoft.lml.model.annotation.PersistentEntity;
import org.paquitosoft.lml.model.annotation.PersistentAttribute;
import org.paquitosoft.lml.model.annotation.AssociatedEntityList;
import org.paquitosoft.lml.model.exception.ReflectionException;
import org.paquitosoft.lml.util.LMLGlobalOperations;
import static org.paquitosoft.lml.util.LMLConstants.*;

/**
*
* @author paquitosoft
*/
public class ModelUtilities {

    private static Logger logger = Logger.getLogger(ModelUtilities.class.getName());
   
    private static HashMap<Class,String> insertQueries = new HashMap<Class,String>();
    private static HashMap<Class,String> readQueries = new HashMap<Class,String>();
    private static HashMap<Class,String> updateQueries = new HashMap<Class,String>();
    private static HashMap<Class,String> deleteQueries = new HashMap<Class,String>();
    private static HashMap<Class,String> baseReadQueries = new HashMap<Class,String>();
    private static HashMap<String,String> joinFinderQueries = new HashMap<String,String>();

    /**
     * Generates the query for creating and entity
     * @param entityClass
     * @return insert query
     */
    public static String getQueryForInsert(Class entityClass) {
       
        String result = insertQueries.get(entityClass);
       
        if (result == null) {
            boolean skipPK = isEntityPKGeneratedByDatabase(entityClass);
            boolean pkSkipped = false;
            StringBuilder sb = new StringBuilder("INSERT INTO ");
            sb.append(getTableName(entityClass));
            sb.append(" (");
            List<Field> fields = getAllPersistentEntityFields(entityClass);
            for (Field f : fields) {
                if (skipPK && isPKField(f)) {
                    pkSkipped = true;                   
                } else {
                    sb.append(getColumnName(f));
                    sb.append(',');
                }
            }
            sb.delete(sb.length() - 1, sb.length());
            sb.append(") VALUES (");
            for (int i = 0; i < (fields.size() - (pkSkipped ? 1 : 0)); i++) {
                sb.append("?,");
            }
            sb.delete(sb.length() - 1, sb.length());
            sb.append(")");
            result = sb.toString();
            insertQueries.put(entityClass, result);
            logger.log(Level.INFO, "INSERT query generated ->" + sb.toString() + "<-");
        }
       
        return result;
    }

    /**
     * Generates the query for delete an entity
     * @param entityClass
     * @return delete query
     */
    public static String getQueryForDelete(Class entityClass) {
       
        String result = deleteQueries.get(entityClass);
       
        if (result == null) {
            StringBuilder sb = new StringBuilder("DELETE FROM ");
            sb.append(getTableName(entityClass));
            sb.append(getWhereClause(entityClass));       
            result = sb.toString();
            deleteQueries.put(entityClass, result);
            logger.log(Level.INFO, "DELETE query generated ->" + sb.toString() + "<-");
        }
       
        return result;
    }

    /**
     * Generates the query for update an entity
     * @param entityClass
     * @return update query
     */
    public static String getQueryForUpdate(Class entityClass) {
       
        String result = updateQueries.get(entityClass);
       
        if (result == null) {
            StringBuilder sb = new StringBuilder("UPDATE ");
            sb.append(getTableName(entityClass));
            sb.append(" SET ");
            List<Field> fields = getAllPersistentEntityFields(entityClass);
            for (Field f : fields) {
                if (!isPKField(f)) {
                    sb.append(getColumnName(f));
                    sb.append("=?, ");
                }               
            }
            sb.delete(sb.length() - 2, sb.length());
            sb.append(getWhereClause(entityClass));       
            result = sb.toString();
            updateQueries.put(entityClass, result);
            logger.log(Level.INFO, "UPDATE query generated ->" + sb.toString() + "<-");
        }
       
        return result;
    }
   
    /**
     * Generates the base query for consulting the table of the entity provided.
     *
     * @param entityClass
     * @return base read query
     */
    public static String getQueryBaseForRead(Class entityClass) {

        String result = baseReadQueries.get(entityClass);

        if (result == null) {
            StringBuilder sb = new StringBuilder("SELECT ");
            ArrayList<Field> fields = getAllPersistentEntityFields(entityClass);
            for (Field f : fields) {
                sb.append(getColumnName(f));
                sb.append(", ");
            }
            sb.delete(sb.length() - 2, sb.length());
            sb.append(" FROM ");
            sb.append(getTableName(entityClass));
            result = sb.toString();
            baseReadQueries.put(entityClass, result);
            logger.log(Level.INFO, "Base FIND query generated ->" + sb.toString() + "<-");
        }

        return result;

    }

    /**
     * Generate the query for read the an entity using its identifiers.
     *
     * @param entityClass
     * @return read query
     */
    public static String getQueryForRead(Class entityClass) {
       
        String result = readQueries.get(entityClass);
       
        if (result == null) {
            result = getQueryBaseForRead(entityClass) + getWhereClause(entityClass);
            readQueries.put(entityClass, result);
            logger.log(Level.INFO, "FIND query generated ->" + result + "<-");
        }
       
        return result;
    }
   
    /**
     * Generates the query to get the entity associated list from another entity
     * when tehy association type is N-M.
     *
     * @param sourceEntityClass
     * @param destinationEntityClass
     * @param joinTableName
     * @return join finder query
     */
    public static String getJoinFinderQuery(Class sourceEntityClass,
            Class destinationEntityClass, String joinTableName) {

        String queryId = sourceEntityClass.getName() + "->" +
                destinationEntityClass.getName();
        String result = joinFinderQueries.get(queryId);

        if (result == null) {

            StringBuilder sb = new StringBuilder(getQueryBaseForRead(destinationEntityClass));
            sb.append(" WHERE ");

            List<String> sourcePkColumnNames = getEntityIdentifiersColumnNames(sourceEntityClass);
            List<String> destinationPkColumnNames = getEntityIdentifiersColumnNames(destinationEntityClass);
            for (int i = 0; i < sourcePkColumnNames.size(); i++) {
                sb.append(destinationPkColumnNames.get(i));
                sb.append(" IN (SELECT ");
                sb.append(destinationPkColumnNames.get(i));
                sb.append(" FROM ");
                sb.append(joinTableName);
                sb.append(" WHERE ");
                sb.append(sourcePkColumnNames.get(i));
                sb.append(" = ?)");
            }

            result = sb.toString();
            joinFinderQueries.put(queryId, result);
            logger.log(Level.INFO, "FIND query generated ->" + result + "<-");
        }

        return result;
    }

    /**
     * Inserts a value into a preparedStatement.
     *
     * @param value
     * @param stm
     * @param index
     * @throws java.sql.SQLException
     */
    public static void insertValueInQuery(Object value, PreparedStatement stm, int index) throws SQLException {
       
        if (value == null) {
            stm.setString(index, null);
        } else if (String.class.equals(value.getClass())) {
            stm.setString(index, (String) value);
        } else if (Integer.class.equals(value.getClass())) {
            if (value != null) {
                stm.setInt(index, (Integer) value);
            } else {
                stm.setObject(index, null);
            }           
        } else if (Long.class.equals(value.getClass())) {
            if (value != null) {
                stm.setLong(index, (Long) value);
            } else {
                stm.setObject(index, null);
            }
        } else if (Double.class.equals(value.getClass())) {
            if (value != null) {
                stm.setDouble(index, (Double) value);
            } else {
                stm.setObject(index, null);
            }
        } else if (Float.class.equals(value.getClass())) {
            if (value != null) {
                stm.setFloat(index, (Float) value);
            } else {
                stm.setObject(index, null);
            }
        } else if (value instanceof Calendar) {
            if (value != null) {
                stm.setTimestamp(index, new Timestamp(((Calendar) value).getTimeInMillis()));
            } else {
                stm.setObject(index, null);
            }           
        } else if (value instanceof Date) {
            if (value != null) {
                stm.setTimestamp(index, new Timestamp(((Date) value).getTime()));
            } else {
                stm.setObject(index, null);
            }
        } else if (Boolean.class.equals(value.getClass())) {
            if (value != null) {
                stm.setBoolean(index, (Boolean) value);
            } else {
                stm.setObject(index, null);
            }
        } else if (Byte.class.equals(value.getClass())) {
            if (value != null) {
                stm.setByte(index, (Byte) value);
            } else {
                stm.setObject(index, null);
            }
        } else if (Short.class.equals(value.getClass())) {
            if (value != null) {
                stm.setShort(index, (Short) value);
            } else {
                stm.setObject(index, null);
            }
        } else if (Character.class.equals(value.getClass())) {
            if (value != null) {
                stm.setString(index, ((Character) value).toString());
            } else {
                stm.setObject(index, null);
            }
        } else if (BigDecimal.class.equals(value.getClass())) {
            if (value != null) {
                stm.setBigDecimal(index, (BigDecimal) value);
            } else {
                stm.setObject(index, null);
            }
        } else {
            stm.setObject(index, value);
        }
       
    }

    /**
     * Gets the value from the resultSet defined by its columName and valueType.
     *
     * @param valueType
     * @param rs
     * @param columnName
     * @return
     * @throws java.sql.SQLException
     */
    public static <T> T getValueFromQuery(Class<T> valueType, ResultSet rs, String columnName) throws SQLException {
       
        T result = null;
       
        if (String.class.equals(valueType)) {
            result = (T) rs.getString(columnName);
        } else if (Integer.class.equals(valueType)) {
            Integer aux = rs.getInt(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Long.class.equals(valueType)) {
            Long aux = rs.getLong(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Double.class.equals(valueType)) {
            Double aux = rs.getDouble(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Float.class.equals(valueType)) {
            Float aux = rs.getFloat(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Calendar.class.equals(valueType)) { 
            Calendar aux1 = null;
            Timestamp aux2 = rs.getTimestamp(columnName);
            if (aux2 != null) {
                    Date time = new Date(aux2.getTime());
                    aux1 = Calendar.getInstance();
                    aux1.setTime(time);
                    result = (T) aux1;
            }           
        } else if (Date.class.equals(valueType)) {
            Timestamp aux = rs.getTimestamp(columnName);
            if (aux != null) {
                    Date time = new Date(aux.getTime());                   
                    result = (T) time;
            }
        } else if (Boolean.class.equals(valueType)) {
            Boolean aux = rs.getBoolean(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Byte.class.equals(valueType)) {
            Byte aux = rs.getByte(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Short.class.equals(valueType)) {
            Short aux = rs.getShort(columnName);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (char.class.equals(valueType) || Character.class.equals(valueType)) {
            String aux = rs.getString(columnName);
            result = (aux != null) ? (T) new Character(aux.charAt(0)) : null;
        } else {           
            result = (T) rs.getObject(columnName);
        }
       
        return result;
    }
       
    /**
     * Gets the value from the resultSet defined by its columName and valueType.
     *
     * @param valueType
     * @param rs
     * @param columnIndex
     * @return
     * @throws java.sql.SQLException
     */
    public static <T> T getValueFromQuery(Class<T> valueType, ResultSet rs, int columnIndex) throws SQLException {
       
        T result = null;
       
        if (String.class.equals(valueType)) {
            result = (T) rs.getString(columnIndex);
        } else if (Integer.class.equals(valueType)) {
            Integer aux = rs.getInt(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Long.class.equals(valueType)) {
            Long aux = rs.getLong(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Double.class.equals(valueType)) {
            Double aux = rs.getDouble(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Float.class.equals(valueType)) {
            Float aux = rs.getFloat(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Calendar.class.equals(valueType)) { 
            Calendar aux1 = null;
            Timestamp aux2 = rs.getTimestamp(columnIndex);
            if (aux2 != null) {
                    Date time = new Date(aux2.getTime());
                    aux1 = Calendar.getInstance();
                    aux1.setTime(time);
                    result = (T) aux1;
            }           
        } else if (Date.class.equals(valueType)) {
            Timestamp aux = rs.getTimestamp(columnIndex);
            if (aux != null) {
                    Date time = new Date(aux.getTime());                   
                    result = (T) time;
            }
        } else if (Boolean.class.equals(valueType)) {
            Boolean aux = rs.getBoolean(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Byte.class.equals(valueType)) {
            Boolean aux = rs.getBoolean(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (Short.class.equals(valueType)) {
            Short aux = rs.getShort(columnIndex);
            result = (rs.wasNull()) ? null : (T) aux;
        } else if (char.class.equals(valueType) || Character.class.equals(valueType)) {
            String aux = rs.getString(columnIndex);
            result = (aux != null) ? (T) new Character(aux.charAt(0)) : null;
        } else {           
            result = (T) rs.getObject(columnIndex);
        }
       
        return result;
    }

    /**
     * Populates an entity from a resultSet. <i>partialEntity</i> indicates whether the resultSet bring only
     * some of the entity attributes.
     * @param entityType
     * @param rs
     * @param partialEntity <b>true</b> when we executed a query that doesn't bring all entity fields
     * @return
     * @throws java.lang.Exception
     */
    public static <T> T createEntityWithValues(Class<T> entityType, ResultSet rs, boolean partialEntity) throws ReflectionException {
       
        T result = null;
       
        try {
           
            result = (T) entityType.newInstance();

            ArrayList<Field> fields = getAllPersistentEntityFields(entityType);

            for (Field f : fields) {
                f.setAccessible(true); // VERY IMPORTANT!!!
                PersistentAttribute annot = f.getAnnotation(PersistentAttribute.class);
                // If this field is not annotated we must ignore it
                if (annot == null) {
                    continue;
                }
                String columnName = getColumnName(f);
                boolean readField = true;
                if (annot.entity()) {

                    // If it is a custom type we need to create a instance an populate its identifier
                    List<Field> pkFields = getEntityIdentifierFields(f.getType());               
                    if (pkFields.size() == 1) {

                        Field pkField = pkFields.get(0);
                        pkField.setAccessible(true); // VERY IMPORTANT!!!
                        Object associated = f.getType().newInstance();
//                        PersistentAttribute at = f.getAnnotation(PersistentAttribute.class);
                        try {
                            // This is done because of finder queries where we don't want all entity fields
                            rs.findColumn(columnName);
                        } catch (SQLException e) {
                            readField = false;
                            if (!partialEntity) {
                                throw e;
                            }
                        }     
                        if (readField) {
                            pkField.set(associated, getValueFromQuery(pkField.getType(), rs, columnName));
                        }
                        f.set(result, associated);

                    } else {
                        // TODO Crear una excepcion especifica para darle significado a este suceso
                        throw new ReflectionException("ERROR: Compound key for associated entity.");
                    }

                } else {
                    // If it is a common type we use the column name from the annotation or
                    // the name of the field if that has not been set
                    try {
                        // This is done because of finder queries where we don't want all entity fields
                        rs.findColumn(columnName);                       
                    } catch (SQLException e) {
                        readField = false;
                        if (!partialEntity) {
                            throw e;
                        }
                    }
                    if (readField) {
                        f.set(result, getValueFromQuery(f.getType(), rs, columnName));
                    }
                }
            }

        } catch (Exception e) {
            logger.log(Level.SEVERE, "Method: getFieldValue()", e);
            throw new ReflectionException(e);
        }
       
        return result;
    }
   
    /**
     * Devuelve todos los atributos marcados como persistentes de las clase,
     * buscando de forma recursiva hacia arriba.
     * @param entityClass
     * @return peristent fields or empty list
     */
    public static ArrayList<Field> getAllPersistentEntityFields(Class entityClass) {
       
        ArrayList<Field> result = new ArrayList<Field>();
       
        Field[] ownFields = entityClass.getDeclaredFields();
        for (int i = 0; i < ownFields.length; i++) {           
            if (ownFields[i].getAnnotation(PersistentAttribute.class) != null) {
                result.add(ownFields[i]);
            }
        }       
       
        Class superClass = entityClass.getSuperclass();
        if (superClass != null) {           
            result.addAll(getAllPersistentEntityFields(superClass));
        }
       
        // Sort fileds by name
        Collections.sort(result, new FieldNameComparator());
       
        return result;
    }

    /**
     * This method returns all primary keys attributes from this entity,
     * sorted by name.
     *
     * @param entityClass
     * @return primary key attributes
     * @throws java.lang.Exception
     */
    public static List<Field> getEntityIdentifierFields(Class entityClass) {
   
        List<Field> result = new ArrayList<Field>();
       
        Field[] fs = entityClass.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            PersistentAttribute fieldAT = fs[i].getAnnotation(PersistentAttribute.class);           
            if (fieldAT != null && fieldAT.primaryKey()) {
                result.add(fs[i]);
            }
        }
       
        // Sort fileds by name
        Collections.sort(result, new FieldNameComparator());
       
        return result;
    }
   
    /**
     * Este metodo me devuelve el nombre de la columna en la tabla correspondiente
     * al atributo de entidad que le proporcionamos. En caso de no tenerlo establecido,
     * devuelve el nombre del atributo.
     * @param persistentField
     * @return column name for the field provided
     */
    public static String getColumnName(Field f) {
       
        String result = f.getName();       
        PersistentAttribute att = f.getAnnotation(PersistentAttribute.class);           
        if (att != null) {
            result = (att.columnName().length() > 0) ? att.columnName().toUpperCase(): f.getName().toUpperCase();
        }           
        return result;
    }

    /**
     * This method onbtains the name of the PK column names from the table
     * of the provided entity.
     *
     * @param entityClass
     * @return primary key column names
     */
    public static List<String> getEntityIdentifiersColumnNames(Class entityClass) {
        List<Field> idFields = getEntityIdentifierFields(entityClass);
        List<String> result = new ArrayList<String>(idFields.size());
        for (Field f : idFields) {
            result.add(getColumnName(f));
        }
        return result;
    }

    /**
     * This methods obtains the table name for a given entity.
     *
     * @param entityClass
     * @return table name for the entity provided
     */
    public static String getTableName(Class entityClass) {
       
        String result = entityClass.getSimpleName();
       
        PersistentEntity att = (PersistentEntity) entityClass.getAnnotation(PersistentEntity.class);
        if (att != null && att.tableName().length() > 0) {
            result = att.tableName();
        }
       
        return result.toUpperCase();
    }

    /**
     * Metodo utilizado para construir la clausula WHERE basica de una consulta
     * con las claves primarias en la entidad proporcionada
     * @param entityClass
     * @return
     * @throws java.lang.Exception
     */
    protected static String getWhereClause(Class entityClass) {
       
        StringBuilder sb = new StringBuilder();
       
        sb.append(" WHERE ");
        List<Field> fields = getEntityIdentifierFields(entityClass);
        for (Field f : fields) {
            sb.append(getColumnName(f));
            sb.append("=? AND ");
        }
        int i = sb.lastIndexOf(" AND ");
        if (i != -1) {
            sb.delete(i, sb.length());
        }
       
        return sb.toString();
    }

    /**
     * Este metodo se utiliza para obtener todos los metodos accesores de una clase (getters y setters) de
     * forma recursiva.
     * accessorPrefix debe ser <b>get</b> o <b>set</b>.
     * @param entityClass
     * @param accessorPrefix debe ser <b>get</b> o <b>set</b>
     * @return
     */
    public static List<Method> getAllPersistentEntityAccessors(Class entityClass, String accessorPrefix) throws ReflectionException {
       
        List<Method> result = new ArrayList<Method>();

        // Ger class methods
        Method[] ownMethods = entityClass.getDeclaredMethods();
        for (int i = 0; i < ownMethods.length; i++) {
            StringBuilder mName = new StringBuilder(ownMethods[i].getName());
            // Pick olny the getter/setter methods
            if (mName.toString().startsWith(accessorPrefix)) {
                mName.delete(0, 3);
                mName.replace(0, 1, String.valueOf(mName.charAt(0)).toUpperCase());
                // Select only those from the annotated fields
                try {
                    if (entityClass.getField(mName.toString()).isAnnotationPresent(PersistentAttribute.class)) {
                        result.add(ownMethods[i]);
                    }
                } catch (Exception e) {
                    logger.log(Level.SEVERE, "Method: getAllPersistentEntityAccessors()", e);
                    throw new ReflectionException(e);
                }
                                               
            }
        }       
       
        // This is to work recursovely upwards
        Class superClass = entityClass.getSuperclass();
        if (superClass != null) {           
            result.addAll(getAllPersistentEntityAccessors(entityClass, accessorPrefix));
        }
       
        // Sort fileds by name
        Collections.sort(result, new FieldNameComparator());
       
        return result;
    }

    /**
     * Devuelve el valor del atributo indicado del objeto proporcionado.
     * @param fieldName
     * @param entity
     * @return
     * @throws java.lang.Exception
     */
    public static Object getFieldValue(String fieldName, Object entity) throws ReflectionException {
       
        Object result = null;
       
        for (Field f : getAllPersistentEntityFields(entity.getClass())) {
            PersistentAttribute antt = f.getAnnotation(PersistentAttribute.class);           
            if ((antt.columnName().length() > 0 && fieldName.equalsIgnoreCase(antt.columnName())) ||
                    fieldName.equalsIgnoreCase(f.getName())){
                try {
                    f.setAccessible(true);
                    if (antt.entity()) {
                        result = getEntityIdentifier(f.get(entity))// TODO Does it worth it to check the identifier here?
                    } else {
                        result = f.get(entity);
                    }                   
                    break;
                } catch (Exception ex) {
                    logger.log(Level.SEVERE, "Method: getFieldValue()", ex);
                    throw new ReflectionException(ex);
                }
            }
        }
       
        return result;
    }
   
    /**
     * This method is used to get all the fields from an entity (recursively) that are
     * annotated with a custom annotation.
     *
     * @param entityClass
     * @param annotationType
     * @return list of fields annotated with <i>annotationType</i> (sorted by name)
     */
    public static ArrayList<Field> getAllAnnotatedEntityFields(Class entityClass, Class annotationType) {
       
        ArrayList<Field> result = new ArrayList<Field>();
       
        Field[] ownFields = entityClass.getDeclaredFields();
        for (int i = 0; i < ownFields.length; i++) {           
            if (ownFields[i].getAnnotation(annotationType) != null) {
                result.add(ownFields[i]);
            }
        }       
       
        Class superClass = entityClass.getSuperclass();
        if (superClass != null) {           
            result.addAll(getAllAnnotatedEntityFields(superClass, annotationType));
        }
       
        // Sort fileds by name
        Collections.sort(result, new FieldNameComparator());
       
        return result;
    }
   
    /**
     * This method is used to get all the entity entity attributes (recursively).
     *
     * @param entityClass
     * @return list of associates attributes (sorted by name)
     */
    public static ArrayList<Field> getAllAssociatedEntityFields(Class entityClass) {
       
        ArrayList<Field> result = new ArrayList<Field>();
       
        Field[] ownFields = entityClass.getDeclaredFields();
        for (int i = 0; i < ownFields.length; i++) {           
            if (ownFields[i].getAnnotation(PersistentAttribute.class) != null &&
                    ownFields[i].getAnnotation(PersistentAttribute.class).entity()) {
                result.add(ownFields[i]);
            }
        }       
       
        Class superClass = entityClass.getSuperclass();
        if (superClass != null) {           
            result.addAll(getAllAssociatedEntityFields(superClass));
        }
       
        // Sort fileds by name
        Collections.sort(result, new FieldNameComparator());
       
        return result;
    }
   
    /**
     * This method is used to get the primary key attributes from
     * this entity.
     * If the primary key is a single value, this value is returned.
     * If the primary key is coumpound, the entity itself is returned.
     * If there is no primary key, a ReflectionException is raised.
     *
     * @param entityClass
     * @return primary key
     */
    public static Object getEntityIdentifier(Object entity) throws ReflectionException {
   
        Object result = null;
       
        int pkCounter = 0;
        Field[] fs = entity.getClass().getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            PersistentAttribute fieldAT = fs[i].getAnnotation(PersistentAttribute.class);           
            if (fieldAT != null && fieldAT.primaryKey()) {
                pkCounter++;
            }
        }
       
        if (pkCounter == 1) {
            try {
                fs[0].setAccessible(true); // TODO Esto no es correcto. Supone que los campos vienen ordenados y la documentacion dice que no es asi. Es necesario cambiar esto.
                result = fs[0].get(entity);
            } catch (IllegalAccessException e) {
                throw new ReflectionException(e);
            }
           
        } else if (pkCounter  > 1) {
            result = entity;
        } else {
            throw new ReflectionException("" + entity.getClass().getName() + " instance has no primary keys.");
        }
       
        return result;
    }
    /**
     * This method is used to create the query we must use to gather a collection of related
     * entities to a specified entity.
     *
     * @return
     */
    public static String generateFindRelatedEntitiesQuery(Field relatedAttribute) throws ReflectionException {
   
        StringBuilder sb = new StringBuilder("SELECT ");
       
        try {
            // Get the foreign key
            String[] fks = relatedAttribute.getAnnotation(AssociatedEntityList.class).externalKey().split(",");
           
            // Get the type of the collection
            Class collectionType = LMLGlobalOperations.getCollectionType(relatedAttribute);
           
            ArrayList<Field> fields = getAllPersistentEntityFields(collectionType);
            for (Field f : fields) {
                sb.append(getColumnName(f));
                sb.append(", ");
            }
            sb.delete(sb.length() - 2, sb.length());
            sb.append(" FROM ");
            sb.append(getTableName(collectionType));
            sb.append(" WHERE ");
            for (int i = 0; i < fks.length; i++) {
                sb.append(fks[i]);
                sb.append("=? AND ");
            }
            int j = sb.lastIndexOf(" AND ");
            if (j != -1) {
                sb.delete(j, sb.length());
            }

        } catch (Exception exception) {
            throw new ReflectionException("ModelUtilities::generateFindRelatedEntitiesQuery -> Most likely this is an error when " +
                    "we try to get the type of the collection.", exception);
        }
       
        return sb.toString();
    }

    /**
     * This method is used to get all the attributes that must be persisted when the
     * entity does.
     *
     * @param entityClass
     * @return list of cascade attributes
     */
    public static List<Field> getCascadeAttributes(Class entityClass) {
   
        List<Field> result = new ArrayList<Field>();
       
        for (Field f : getAllAnnotatedEntityFields(entityClass, PersistentAttribute.class)) {
            if (f.getAnnotation(PersistentAttribute.class).entity() &&
                    !AssociationType.NONE.equals(f.getAnnotation(PersistentAttribute.class).saveAssociationType()) &&
                    !AssociationType.NONE.equals(f.getAnnotation(PersistentAttribute.class).removeAssociationType())) {
                result.add(f);
            }
        }
       
        for (Field f : getAllAnnotatedEntityFields(entityClass, AssociatedEntityList.class)) {
            if (!AssociationType.NONE.equals(f.getAnnotation(AssociatedEntityList.class).saveAssociationType()) &&
                    !AssociationType.NONE.equals(f.getAnnotation(AssociatedEntityList.class).removeAssociationType())) {
                result.add(f);
            }
        }
       
        return result;
    }

    /**
     * This method is used to gather the class of the primary key from an entity.
     *
     * @param entityType
     * @return primary key class or <b>null</b> if there is no primary key or it is <b>compound</b>
     */
    public static Class getEntityIdType(Class entityType) {
   
        Class result = null;
       
        int pkCounter = 0;
        Field[] fs = entityType.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            PersistentAttribute fieldAT = fs[i].getAnnotation(PersistentAttribute.class);           
            if (fieldAT != null && fieldAT.primaryKey()) {
                fs[0].setAccessible(true);
                result = fs[0].getType();
                if (++pkCounter > 1) {
                    return null;
                }
            }
        }
       
        return result;
    }

    /**
     * This method gets the associationType for the fiel depending on the persistence persistenceMode
     * provided.<br/>
     * (default value is AssociationType.NONE)
     *
     * @param persistentField
     * @param persistenceMode
     * @return association type (default AssociationType.NONE)
     */
    public static AssociationType getAssociationType(Field persistentField, byte persistenceMode) {
   
        AssociationType result = AssociationType.NONE;
       
        if (PERSIST_MODE_DELETE == persistenceMode) {
            PersistentAttribute att = persistentField.getAnnotation(PersistentAttribute.class);
            if (att != null) {
                result = att.removeAssociationType();
            } else {
                result = persistentField.getAnnotation(AssociatedEntityList.class).removeAssociationType();
            }
        } else if (PERSIST_MODE_SAVE == persistenceMode) {
            PersistentAttribute att = persistentField.getAnnotation(PersistentAttribute.class);
            if (att != null) {
                result = att.saveAssociationType();
            } else {
                result = persistentField.getAnnotation(AssociatedEntityList.class).saveAssociationType();
            }
        } else if (PERSIST_MODE_UPDATE == persistenceMode) {
            PersistentAttribute att = persistentField.getAnnotation(PersistentAttribute.class);
            if (att != null) {
                result = att.updateAssociationType();
            } else {
                result = persistentField.getAnnotation(AssociatedEntityList.class).updateAssociationType();
            }
        }
               
        return result;
    }

    /**
     * This method checks for a class to see if it's an entity class with a database
     * generated key.
     *
     * @param entityClass
     * @return <b>true</b> when entity's primary key is generated by the database
     */
    public static boolean isEntityPKGeneratedByDatabase(Class entityClass) {
        boolean result = true;
        PersistentEntity pr = (PersistentEntity) entityClass.getAnnotation(PersistentEntity.class);
        if (pr != null && pr.generateKey()) {
            result = false;
        }
        return result;
    }
    /**
     * This method is used to check wether provided field represents
     * a primary key.
     *
     * @param f
     * @return <b>true</b> when it represents a primary key
     */
    public static boolean isPKField(Field f) {
        boolean result = false;
        if (f != null) {
            PersistentAttribute pa = f.getAnnotation(PersistentAttribute.class);
            if (pa != null && pa.primaryKey()) {
                result = true;
            }
        }       
        return result;
    }
   
}
TOP

Related Classes of org.paquitosoft.lml.model.util.ModelUtilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.