Java tutorial
/** * * 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); } }