lucee.runtime.orm.hibernate.HibernateCaster.java Source code

Java tutorial

Introduction

Here is the source code for lucee.runtime.orm.hibernate.HibernateCaster.java

Source

/**
 *
 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
 *
 * 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 2.1 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, see <http://www.gnu.org/licenses/>.
 * 
 **/
package lucee.runtime.orm.hibernate;

import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import lucee.commons.lang.types.RefBoolean;
import lucee.loader.util.Util;
import lucee.runtime.Component;
import lucee.runtime.ComponentScope;
import lucee.runtime.PageContext;
import lucee.runtime.component.Property;
import lucee.runtime.db.SQLCaster;
import lucee.runtime.db.SQLItem;
import lucee.runtime.exp.PageException;
import lucee.runtime.op.Caster;
import lucee.runtime.orm.ORMEngine;
import lucee.runtime.orm.ORMSession;
import lucee.runtime.orm.ORMUtil;
import lucee.runtime.type.Array;
import lucee.runtime.type.Collection;
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.Query;
import lucee.runtime.type.Struct;
import lucee.runtime.type.util.QueryUtil;

import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;

public class HibernateCaster {

    private static final int NULL = -178696;

    public static Object toCFML(Object src) {
        if (src == null)
            return null;
        if (src instanceof Collection)
            return src;

        if (src instanceof List) {
            return toCFML((List) src);
        }
        /*if(src instanceof Map){
           return toCFML(pc,(Map) src);
        }*/
        return src;
    }

    public static Array toCFML(List src) {
        int size = src.size();

        Array trg = CommonUtil.createArray();
        for (int i = 0; i < size; i++) {
            trg.setEL(i + 1, toCFML(src.get(i)));
        }
        return trg;
    }

    /*public static Object toCFML(PageContext pc,Map src) throws PageException {
           
       Object type =src.remove("$type$");
       if(type instanceof String){
         
     Component cfc = toComponent(pc, (String)type);
     return toCFML(pc,src, cfc);
       }
           
           
       Iterator<Map.Entry<String, Object>> it = src.entrySet().iterator();
    Struct trg=CommonUtil.createStruct();
    Map.Entry<String, Object> entry;
    while(it.hasNext()){
     entry=it.next();
        trg.setEL(entry.getKey(),toCFML(pc,entry.getValue()));
    }
    return trg;
    }*/

    public static String getEntityName(Component cfc) {

        String name = null;
        try {
            name = CommonUtil.toString(HibernateUtil.getMetaStructItem(cfc, CommonUtil.ENTITY_NAME), null);
        } catch (Throwable t) {
            try {
                Struct md = cfc.getMetaData(CommonUtil.pc());
                name = CommonUtil.toString(md.get(CommonUtil.ENTITY_NAME), null);

            } catch (PageException e) {
            }
        }

        if (!Util.isEmpty(name)) {
            return name;
        }
        return getName(cfc);

    }

    private static String getName(Component cfc) {
        String name = null;
        // MUSTMUST cfc.getName() should return the real case, this should not be needed
        name = cfc.getPageSource().getDisplayPath();
        name = CommonUtil.last(name, "\\/");
        int index = name.lastIndexOf('.');
        name = name.substring(0, index);
        return name;
    }

    public static int cascade(ORMSession session, String cascade) throws PageException {
        int c = cascade(cascade, -1);
        if (c != -1)
            return c;
        throw ExceptionUtil.createException(session, null,
                "invalid cascade defintion [" + cascade
                        + "], valid values are [all,all-delete-orphan,delete,delete-orphan,refresh,save-update]",
                null);
    }

    public static int cascade(String cascade, int defaultValue) {
        cascade = cascade.trim().toLowerCase();
        if ("all".equals(cascade))
            return HibernateConstants.CASCADE_ALL;

        if ("save-update".equals(cascade))
            return HibernateConstants.CASCADE_SAVE_UPDATE;
        if ("save_update".equals(cascade))
            return HibernateConstants.CASCADE_SAVE_UPDATE;
        if ("saveupdate".equals(cascade))
            return HibernateConstants.CASCADE_SAVE_UPDATE;

        if ("delete".equals(cascade))
            return HibernateConstants.CASCADE_DELETE;

        if ("delete-orphan".equals(cascade))
            return HibernateConstants.CASCADE_DELETE_ORPHAN;
        if ("delete_orphan".equals(cascade))
            return HibernateConstants.CASCADE_DELETE_ORPHAN;
        if ("deleteorphan".equals(cascade))
            return HibernateConstants.CASCADE_DELETE_ORPHAN;

        if ("all-delete-orphan".equals(cascade))
            return HibernateConstants.CASCADE_ALL_DELETE_ORPHAN;
        if ("all_delete_orphan".equals(cascade))
            return HibernateConstants.CASCADE_ALL_DELETE_ORPHAN;
        if ("alldeleteorphan".equals(cascade))
            return HibernateConstants.CASCADE_ALL_DELETE_ORPHAN;

        if ("refresh".equals(cascade))
            return HibernateConstants.REFRESH;

        return defaultValue;
    }

    public static int collectionType(ORMSession session, String strCollectionType) throws PageException {
        int ct = collectionType(strCollectionType, -1);
        if (ct != -1)
            return ct;
        throw ExceptionUtil.createException(session, null,
                "invalid collectionType defintion [" + strCollectionType + "], valid values are [array,struct]",
                null);
    }

    public static int collectionType(String strCollectionType, int defaultValue) {
        strCollectionType = strCollectionType.trim().toLowerCase();
        if ("struct".equals(strCollectionType))
            return HibernateConstants.COLLECTION_TYPE_STRUCT;
        if ("array".equals(strCollectionType))
            return HibernateConstants.COLLECTION_TYPE_ARRAY;

        return defaultValue;
    }

    public static String toHibernateType(ColumnInfo info, String type, String defaultValue) {

        // no type defined
        if (Util.isEmpty(type, true)) {
            return HibernateCaster.toHibernateType(info, defaultValue);
        }

        // type defined
        String tmp = HibernateCaster.toHibernateType(type, null);
        if (tmp != null)
            return tmp;

        if (info != null) {
            tmp = HibernateCaster.toHibernateType(info, defaultValue);
            return tmp;
        }
        return defaultValue;

    }

    public static int toSQLType(String type, int defaultValue) {
        type = type.trim().toLowerCase();
        type = toHibernateType(type, type);
        if ("long".equals(type))
            return Types.BIGINT;
        if ("binary".equals(type))
            return Types.BINARY;
        if ("boolean".equals(type))
            return Types.BIT;
        if ("blob".equals(type))
            return Types.BLOB;
        if ("boolean".equals(type))
            return Types.BOOLEAN;
        if ("character".equals(type))
            return Types.CHAR;
        if ("clob".equals(type))
            return Types.CLOB;
        if ("date".equals(type))
            return Types.DATE;
        if ("big_decimal".equals(type))
            return Types.DECIMAL;
        if ("big_integer".equals(type))
            return Types.NUMERIC;
        if ("double".equals(type))
            return Types.DOUBLE;
        if ("float".equals(type))
            return Types.FLOAT;
        if ("integer".equals(type))
            return Types.INTEGER;
        if ("binary".equals(type))
            return Types.VARBINARY;
        if ("string".equals(type))
            return Types.VARCHAR;
        if ("short".equals(type))
            return Types.SMALLINT;
        if ("time".equals(type))
            return Types.TIME;
        if ("timestamp".equals(type))
            return Types.TIMESTAMP;
        if ("byte".equals(type))
            return Types.TINYINT;

        return defaultValue;
    }

    public static String toHibernateType(ColumnInfo info, String defaultValue) {
        if (info == null)
            return defaultValue;

        String rtn = toHibernateType(info.getType(), info.getSize(), null);
        if (rtn != null)
            return rtn;
        return toHibernateType(info.getTypeName(), defaultValue);
    }

    public static String toHibernateType(int type, int size, String defaultValue) {
        // MUST do better
        switch (type) {
        case Types.ARRAY:
            return "";
        case Types.BIGINT:
            return "long";
        case Types.BINARY:
            return "binary";
        case Types.BIT:
            return "boolean";
        case Types.BLOB:
            return "blob";
        case Types.BOOLEAN:
            return "boolean";
        case Types.CHAR:
            return "string";
        //if(size>1) return "string";
        //return "character";
        case Types.CLOB:
            return "clob";
        //case Types.DATALINK: return "";
        case Types.DATE:
            return "date";
        case Types.DECIMAL:
            return "big_decimal";
        //case Types.DISTINCT: return "";
        case Types.DOUBLE:
            return "double";
        case Types.FLOAT:
            return "float";
        case Types.INTEGER:
            return "integer";
        //case Types.JAVA_OBJECT: return "";
        case Types.LONGVARBINARY:
            return "binary";
        case Types.LONGVARCHAR:
            return "string";
        //case Types.NULL: return "";
        case Types.NUMERIC:
            return "big_decimal";
        //case Types.OTHER: return "";
        //case Types.REAL: return "";
        //case Types.REF: return "";
        case Types.SMALLINT:
            return "short";
        //case Types.STRUCT: return "";
        case Types.TIME:
            return "time";
        case Types.TIMESTAMP:
            return "timestamp";
        case Types.TINYINT:
            return "byte";
        case Types.VARBINARY:
            return "binary";
        case Types.NVARCHAR:
            return "string";
        case Types.VARCHAR:
            return "string";
        }
        return defaultValue;
    }

    public static String toHibernateType(ORMSession session, String type) throws PageException {
        String res = toHibernateType(type, null);
        if (res == null)
            throw ExceptionUtil.createException(session, null, "the type [" + type + "] is not supported", null);
        return res;
    }

    // calendar_date: A type mapping for a Calendar object that represents a date
    //calendar: A type mapping for a Calendar object that represents a datetime.
    public static String toHibernateType(String type, String defaultValue) {
        type = type.trim().toLowerCase();
        type = Util.replace(type, "java.lang.", "", true);
        type = Util.replace(type, "java.util.", "", true);
        type = Util.replace(type, "java.sql.", "", true);

        // return same value
        if ("long".equals(type))
            return type;
        if ("binary".equals(type))
            return type;
        if ("boolean".equals(type))
            return type;
        if ("blob".equals(type))
            return "binary";
        if ("boolean".equals(type))
            return type;
        if ("character".equals(type))
            return type;
        if ("clob".equals(type))
            return "text";
        if ("date".equals(type))
            return type;
        if ("big_decimal".equals(type))
            return type;
        if ("double".equals(type))
            return type;
        if ("float".equals(type))
            return type;
        if ("integer".equals(type))
            return type;
        if ("binary".equals(type))
            return type;
        if ("string".equals(type))
            return type;
        if ("big_integer".equals(type))
            return type;
        if ("short".equals(type))
            return type;
        if ("time".equals(type))
            return type;
        if ("timestamp".equals(type))
            return type;
        if ("byte".equals(type))
            return type;
        if ("binary".equals(type))
            return type;
        if ("string".equals(type))
            return type;
        if ("text".equals(type))
            return type;
        if ("calendar".equals(type))
            return type;
        if ("calendar_date".equals(type))
            return type;
        if ("locale".equals(type))
            return type;
        if ("timezone".equals(type))
            return type;
        if ("currency".equals(type))
            return type;

        if ("imm_date".equals(type))
            return type;
        if ("imm_time".equals(type))
            return type;
        if ("imm_timestamp".equals(type))
            return type;
        if ("imm_calendar".equals(type))
            return type;
        if ("imm_calendar_date".equals(type))
            return type;
        if ("imm_serializable".equals(type))
            return type;
        if ("imm_binary".equals(type))
            return type;

        // return different value
        if ("bigint".equals(type))
            return "long";
        if ("bit".equals(type))
            return "boolean";

        if ("int".equals(type))
            return "integer";
        if ("char".equals(type))
            return "character";

        if ("bool".equals(type))
            return "boolean";
        if ("yes-no".equals(type))
            return "yes_no";
        if ("yesno".equals(type))
            return "yes_no";
        if ("yes_no".equals(type))
            return "yes_no";
        if ("true-false".equals(type))
            return "true_false";
        if ("truefalse".equals(type))
            return "true_false";
        if ("true_false".equals(type))
            return "true_false";
        if ("varchar".equals(type))
            return "string";
        if ("big-decimal".equals(type))
            return "big_decimal";
        if ("bigdecimal".equals(type))
            return "big_decimal";
        if ("java.math.bigdecimal".equals(type))
            return "big_decimal";
        if ("big-integer".equals(type))
            return "big_integer";
        if ("biginteger".equals(type))
            return "big_integer";
        if ("bigint".equals(type))
            return "big_integer";
        if ("java.math.biginteger".equals(type))
            return "big_integer";
        if ("byte[]".equals(type))
            return "binary";
        if ("serializable".equals(type))
            return "serializable";

        if ("datetime".equals(type))
            return "timestamp";
        if ("numeric".equals(type))
            return "double";
        if ("number".equals(type))
            return "double";
        if ("numeric".equals(type))
            return "double";
        if ("char".equals(type))
            return "character";
        if ("nchar".equals(type))
            return "character";
        if ("decimal".equals(type))
            return "double";
        if ("eurodate".equals(type))
            return "timestamp";
        if ("usdate".equals(type))
            return "timestamp";
        if ("int".equals(type))
            return "integer";
        if ("varchar".equals(type))
            return "string";
        if ("nvarchar".equals(type))
            return "string";

        return defaultValue;

        // FUTURE
        /*
            
        add support for 
        - any, object,other
            
        add support for custom types https://issues.jboss.org/browse/LUCEE-1341
        - array
         - base64
         - guid
          - memory
         - node, xml
         - query
         - struct
          - uuid
          - variablename, variable_name
         - variablestring, variable_string
             
        */

    }

    public static Object toHibernateValue(PageContext pc, Object value, String type) throws PageException {
        type = toHibernateType(type, null);
        // return same value
        if ("long".equals(type))
            return Caster.toLong(value);
        if ("binary".equals(type) || "imm_binary".equals(type))
            return Caster.toBinary(value);
        if ("boolean".equals(type) || "yes_no".equals(type) || "true_false".equals(type))
            return Caster.toBoolean(value);
        if ("character".equals(type))
            return Caster.toCharacter(value);
        if ("date".equals(type) || "imm_date".equals(type))
            return Caster.toDatetime(value, pc.getTimeZone());
        if ("big_decimal".equals(type))
            return Caster.toBigDecimal(value);
        if ("double".equals(type))
            return Caster.toDouble(value);
        if ("float".equals(type))
            return Caster.toFloat(value);
        if ("integer".equals(type))
            return Caster.toInteger(value);
        if ("string".equals(type))
            return Caster.toString(value);
        if ("big_integer".equals(type))
            return new BigInteger(Caster.toString(value));
        if ("short".equals(type))
            return Caster.toShort(value);
        if ("time".equals(type) || "imm_time".equals(type))
            return new Time(Caster.toDate(value, pc.getTimeZone()).getTime());
        if ("timestamp".equals(type) || "imm_timestamp".equals(type))
            return new Timestamp(Caster.toDate(value, pc.getTimeZone()).getTime());
        if ("byte".equals(type))
            return Caster.toBinary(value);
        if ("text".equals(type))
            return Caster.toString(value);
        if ("calendar".equals(type) || "calendar_date".equals(type) || "imm_calendar".equals(type)
                || "imm_calendar_date".equals(type))
            return Caster.toCalendar(Caster.toDateTime(value, pc.getTimeZone()), pc.getTimeZone(), pc.getLocale());
        if ("locale".equals(type))
            return Caster.toLocale(Caster.toString(value));
        if ("timezone".equals(type))
            return Caster.toTimeZone(value, null);
        if ("currency".equals(type))
            return value;

        if ("imm_serializable".equals(type))
            return value;
        if ("serializable".equals(type))
            return "serializable";

        return value;
    }

    /**
     * translate CFMl specific types to Hibernate/SQL specific types
     * @param engine
     * @param ci
     * @param value
     * @return
     * @throws PageException
     */
    public static Object toSQL(ColumnInfo ci, Object value, RefBoolean isArray) throws PageException {
        return toSQL(ci.getType(), value, isArray);
    }

    /**
     * translate CFMl specific types to Hibernate/SQL specific types
     * @param engine
     * @param type
     * @param value
     * @return
     * @throws PageException
     */
    public static Object toSQL(Type type, Object value, RefBoolean isArray) throws PageException {
        int t = toSQLType(type.getName(), Types.OTHER);
        if (t == Types.OTHER)
            return value;
        return toSQL(t, value, isArray);
    }

    /**
     * translate CFMl specific type to SQL specific types
     * @param engine
     * @param sqlType
     * @param value
     * @return
     * @throws PageException
     */
    private static Object toSQL(int sqlType, Object value, RefBoolean isArray) throws PageException {
        if (isArray != null)
            isArray.setValue(false);
        SQLItem item = CommonUtil.toSQLItem(value, sqlType);
        try {
            return SQLCaster.toSqlType(item);
        } catch (PageException pe) {
            // pherhaps it is a array of this type 
            if (isArray != null && CommonUtil.isArray(value)) {
                Object[] src = CommonUtil.toNativeArray(value);
                ArrayList<Object> trg = new ArrayList<Object>();
                for (int i = 0; i < src.length; i++) {
                    try {
                        trg.add(SQLCaster.toSqlType(CommonUtil.toSQLItem(src[i], sqlType)));
                    } catch (PageException inner) {
                        throw pe;
                    }
                }
                isArray.setValue(true);
                return CommonUtil.toArray(trg);

            }
            throw pe;
        }

    }

    public static lucee.runtime.type.Query toQuery(PageContext pc, HibernateORMSession session, Object obj,
            String name) throws PageException {
        Query qry = null;
        // a single entity
        if (!CommonUtil.isArray(obj)) {
            qry = toQuery(pc, session, HibernateCaster.toComponent(obj), name, null, 1, 1);
        }

        // a array of entities
        else {
            Array arr = CommonUtil.toArray(obj);
            int len = arr.size();
            if (len > 0) {
                Iterator<Object> it = arr.valueIterator();
                int row = 1;
                while (it.hasNext()) {
                    qry = toQuery(pc, session, HibernateCaster.toComponent(it.next()), name, qry, len, row++);
                }
            } else
                qry = CommonUtil.createQuery(new Collection.Key[0], 0, "orm");
        }

        if (qry == null) {
            if (!Util.isEmpty(name))
                throw ExceptionUtil.createException(session, null,
                        "there is no entity inheritance that match the name [" + name + "]", null);
            throw ExceptionUtil.createException(session, null, "cannot create query", null);
        }
        return qry;
    }

    private static Query toQuery(PageContext pc, HibernateORMSession session, Component cfc, String entityName,
            Query qry, int rowcount, int row) throws PageException {
        // inheritance mapping
        if (!Util.isEmpty(entityName)) {
            //String cfcName = toComponentName(HibernateCaster.toComponent(pc, entityName));
            return inheritance(pc, session, cfc, qry, entityName);
        }
        return populateQuery(pc, session, cfc, qry);
    }

    private static Query populateQuery(PageContext pc, HibernateORMSession session, Component cfc, Query qry)
            throws PageException {
        Property[] properties = CommonUtil.getProperties(cfc, true, true, false, false);
        String dsn = ORMUtil.getDataSourceName(pc, cfc);
        ComponentScope scope = cfc.getComponentScope();
        HibernateORMEngine engine = (HibernateORMEngine) session.getEngine();

        // init
        if (qry == null) {
            SessionFactory factory = session.getRawSessionFactory(dsn);
            ClassMetadata md = factory.getClassMetadata(getEntityName(cfc));
            Array names = CommonUtil.createArray();
            Array types = CommonUtil.createArray();
            String name;
            //ColumnInfo ci;
            int t;
            Object obj;
            Struct sct;
            String fieldType;
            for (int i = 0; i < properties.length; i++) {
                obj = properties[i].getMetaData();
                if (obj instanceof Struct) {
                    sct = (Struct) obj;
                    fieldType = CommonUtil.toString(sct.get(CommonUtil.FIELDTYPE, null), null);
                    if ("one-to-many".equalsIgnoreCase(fieldType) || "many-to-many".equalsIgnoreCase(fieldType)
                            || "many-to-one".equalsIgnoreCase(fieldType)
                            || "one-to-one".equalsIgnoreCase(fieldType))
                        continue;

                }

                name = HibernateUtil.validateColumnName(md, properties[i].getName(), null);
                //if(columnsInfo!=null)ci=(ColumnInfo) columnsInfo.get(name,null);
                //else ci=null;
                names.append(name);
                if (name != null) {

                    t = HibernateCaster.toSQLType(HibernateUtil.getPropertyType(md, name).getName(), NULL);
                    if (t == NULL)
                        types.append("object");
                    else
                        types.append(SQLCaster.toStringType(t));
                } else
                    types.append("object");
            }

            qry = CommonUtil.createQuery(names, types, 0, getEntityName(cfc));

        }
        // check
        else if (engine.getMode() == ORMEngine.MODE_STRICT) {
            if (!qry.getName().equals(getEntityName(cfc)))
                throw ExceptionUtil.createException(session, null,
                        "can only merge entities of the same kind to a query", null);
        }

        // populate
        Key[] names = QueryUtil.getColumnNames(qry);

        int row = qry.addRow();
        for (int i = 0; i < names.length; i++) {
            qry.setAtEL(names[i], row, scope.get(names[i], null));
        }
        return qry;
    }

    private static Query inheritance(PageContext pc, HibernateORMSession session, Component cfc, Query qry,
            String entityName) throws PageException {
        Property[] properties = cfc.getProperties(true);
        ComponentScope scope = cfc.getComponentScope();
        Object value;
        Array arr;
        for (int i = 0; i < properties.length; i++) {
            value = scope.get(CommonUtil.createKey(properties[i].getName()), null);
            if (value instanceof Component) {
                qry = inheritance(pc, session, qry, cfc, (Component) value, entityName);
            } else if (CommonUtil.isArray(value)) {
                arr = CommonUtil.toArray(value);
                Iterator<Object> it = arr.valueIterator();
                while (it.hasNext()) {
                    value = it.next();
                    if (value instanceof Component) {
                        qry = inheritance(pc, session, qry, cfc, (Component) value, entityName);
                    }
                }
            }
        }
        return qry;
    }

    private static Query inheritance(PageContext pc, HibernateORMSession session, Query qry, Component parent,
            Component child, String entityName) throws PageException {
        if (getEntityName(child).equalsIgnoreCase(entityName))
            return populateQuery(pc, session, child, qry);
        return inheritance(pc, session, child, qry, entityName);// MUST geh ACF auch so tief?
    }

    /**
     * return the full name (package and name) of a component
     * @param cfc
     * @return
     */
    public static String toComponentName(Component cfc) {
        return cfc.getPageSource().getComponentName();
    }

    public static Component toComponent(Object obj) throws PageException {
        return CommonUtil.toComponent(obj);
    }
}