Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.mentabean.jdbc.AnsiSQLBeanSession Maven / Gradle / Ivy
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* MentaBean => http://www.mentabean.org
* Author: Sergio Oliveira Jr. ([email protected] )
*/
package org.mentabean.jdbc;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.mentabean.BeanConfig;
import org.mentabean.BeanException;
import org.mentabean.BeanManager;
import org.mentabean.BeanSession;
import org.mentabean.DBField;
import org.mentabean.DBType;
import org.mentabean.event.TriggerDispatcher;
import org.mentabean.event.TriggerDispatcher.Type;
import org.mentabean.event.TriggerEvent;
import org.mentabean.event.TriggerListener;
import org.mentabean.sql.TableAlias;
import org.mentabean.type.AutoIncrementType;
import org.mentabean.type.AutoTimestampType;
import org.mentabean.type.NowOnInsertAndUpdateTimestampType;
import org.mentabean.type.NowOnInsertTimestampType;
import org.mentabean.type.NowOnUpdateTimestampType;
import org.mentabean.type.SizedType;
import org.mentabean.util.InjectionUtils;
import org.mentabean.util.Limit;
import org.mentabean.util.OrderBy;
import org.mentabean.util.PropertiesProxy;
import org.mentabean.util.SQLUtils;
/**
* The bean session implementation based on JDBC and SQL.
*
* @author soliveira
*/
public class AnsiSQLBeanSession implements BeanSession {
protected static boolean DEBUG = false;
protected static boolean DEBUG_NATIVE = false;
/* The loaded map will be cleared when the session dies */
protected IdentityHashMap> loaded = new IdentityHashMap>();
protected Connection conn;
protected final BeanManager beanManager;
protected final TriggerDispatcher dispatcher = new TriggerDispatcher();
/**
* Creates a JdbcBeanSession with a BeanManager and a Connection.
*
* @param beanManager
* The bean manager
* @param conn
* The database connection
*/
public AnsiSQLBeanSession(final BeanManager beanManager, final Connection conn) {
this.beanManager = beanManager;
this.conn = conn;
}
/**
* Turn SQL debugging on and off.
*
* @param b
* true if it should be debugged
*/
public static void debugSql(boolean b) {
DEBUG = b;
}
/**
* Turn SQL native queries debugging on and off.
*
* @param b
* true if it should be debugged
*/
public static void debugNativeSql(boolean b) {
DEBUG_NATIVE = b;
}
/**
* Get the connection associated with this JdbcBeanSession.
*
* @return the database connection
*/
@Override
public Connection getConnection() {
return conn;
}
/**
* Get the command representing 'now' in this database. This base implementation returns null, in other words, no now command will be used.
*
* @return the command for now in this database (now(), sysdate, etc)
*/
protected String getCurrentTimestampCommand() {
return null;
}
/**
* Get a value from a bean through reflection.
*
* @param bean
* @param fieldName
* @return The value of a bean property
*/
protected Object getValueFromBean(final Object bean, final String fieldName) {
return getValueFromBean(bean, fieldName, null);
}
public static String[] getProperties(Object[] names) {
if (names != null) {
for(Object o : names) {
if (o instanceof String) {
PropertiesProxy.addPropertyName((String) o);
}
}
}
if (PropertiesProxy.hasProperties()) {
return PropertiesProxy.getPropertyNames();
} else {
return null;
}
}
/**
* Get a value from a bean through reflection.
*
* @param bean
* @param fieldName
* @param m
* @return The value of a bean property
*/
protected Object getValueFromBean(final Object bean, final String fieldName, Method m) {
int index;
if ((index = fieldName.lastIndexOf(".")) > 0) {
String chain = fieldName.substring(0, index);
String lastField = fieldName.substring(index + 1);
Object deepestBean = getDeepestBean(bean, chain, false);
if (deepestBean == null) return null;
return getValueFromBean(deepestBean, lastField, m);
}
if (m == null) {
m = InjectionUtils.findMethodToGet(bean.getClass(), fieldName);
}
if (m == null) {
throw new BeanException("Cannot find method to get field from bean: " +
"Class: " + bean.getClass() + ", field: " + fieldName);
}
Object value = null;
try {
value = m.invoke(bean, (Object[]) null);
return value;
} catch (Exception e) {
throw new BeanException(e);
}
}
private static void checkPK(final Object value, final DBField dbField) {
if (value == null) {
throw new BeanException("pk is missing: " + dbField);
} else if (value instanceof Number) {
final Number n = (Number) value;
if (n.doubleValue() <= 0) {
throw new BeanException("Number pk is missing: " + dbField);
}
}
}
@Override
public boolean load(Object bean) {
return loadImpl(bean, null, null);
}
@Override
public boolean load(Object bean, Object... properties) {
return loadImpl(bean, getProperties(properties), null);
}
@Override
public boolean loadMinus(Object bean, Object... minus) {
return loadImpl(bean, null, getProperties(minus));
}
protected boolean loadImpl(final Object bean, String[] properties, String[] minus) {
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc == null) {
throw new BeanException("Cannot find bean config: " + bean.getClass());
}
if (bc.getNumberOfFields() == 0) {
throw new BeanException("BeanConfig has zero fields: " + bc);
}
final StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
sb.append("SELECT ");
Iterator iter = bc.fields();
int count = 0;
while (iter.hasNext()) {
DBField field = iter.next();
final String fieldName = field.getDbName();
if (!field.isPK()) { // always load the PK...
if (properties != null && !checkArray(fieldName, properties, bc)) {
continue;
}
if (minus != null && checkArray(fieldName, minus, bc)) {
continue;
}
}
if (count++ > 0) {
sb.append(',');
}
sb.append(fieldName);
}
sb.append(" FROM ").append(bc.getTableName()).append(" WHERE ");
if (!bc.hasPK()) {
throw new BeanException("Cannot load bean without a PK!");
}
iter = bc.pks();
count = 0;
final List values = new LinkedList();
while (iter.hasNext()) {
final DBField dbField = iter.next();
final String fieldName = dbField.getName();
final String dbFieldName = dbField.getDbName();
final Object value = getValueFromBean(bean, fieldName);
checkPK(value, dbField);
if (count++ > 0) {
sb.append(" AND ");
}
sb.append(dbFieldName).append("=?");
values.add(new Value(dbField, value));
}
if (values.isEmpty()) {
throw new BeanException("Bean is empty: " + bean + " / " + bc);
}
if (conn == null) {
throw new BeanException("Connection is null!");
}
PreparedStatement stmt = null;
ResultSet rset = null;
try {
if (DEBUG) {
System.out.println("LOAD SQL: " + sb.toString());
}
stmt = conn.prepareStatement(sb.toString());
final Iterator iter2 = values.iterator();
int index = 0;
while (iter2.hasNext()) {
final Value v = iter2.next();
v.field.getType().bindToStmt(stmt, ++index, v.value);
}
rset = stmt.executeQuery();
if (DEBUG_NATIVE) {
System.out.println("LOAD SQL (NATIVE): " + stmt);
}
index = 0;
final Map fieldsLoaded = new HashMap();
if (rset.next()) {
iter = bc.fields();
while (iter.hasNext()) {
final DBField f = iter.next();
final String fieldName = f.getName();
if (!f.isPK()) {
if (properties != null && !checkArray(fieldName, properties, bc)) {
continue;
}
if (minus != null && checkArray(fieldName, minus, bc)) {
continue;
}
}
final DBType type = f.getType();
final Object value = type.getFromResultSet(rset, ++index);
injectValue(bean, fieldName, value, type.getTypeClass());
fieldsLoaded.put(fieldName, new Value(f, value));
}
} else {
return false;
}
if (rset.next()) {
throw new BeanException("Load returned more than one row!");
}
loaded.put(bean, fieldsLoaded);
return true;
} catch (Exception e) {
throw new BeanException(e);
} finally {
close(stmt, rset);
}
}
private Object getDeepestBean(Object target, String name, boolean create) {
int index;
if ((index = name.indexOf('.')) > 0) {
String fieldName = name.substring(0, index);
String remainingName = name.substring(index + 1);
Object bean = getPropertyBean(target, fieldName, create);
return getDeepestBean(bean, remainingName, create);
}
return getPropertyBean(target, name, create);
}
/**
* Get a value from target through reflection and tries to create a new instance if create parameter is true
* @param target
* @param name
* @param create
* @return The value from bean
*/
protected Object getPropertyBean(Object target, String name, boolean create) {
Object value = getValueFromBean(target, name);
if (value == null && create) {
// try to instantiate, must have a default constructor!
Class> beanClass = InjectionUtils.findPropertyType(target.getClass(), name);
if (beanClass == null) {
throw new BeanException("Cannot find property type: " + target.getClass() + " " + name);
}
try {
//TODO instantiate bean
value = beanClass.newInstance();
} catch(Exception e) {
value = getAbstractValue(target.getClass(), name);
}
// don't forget to inject in the target so next time it is there...
injectValue(target, name, value, beanClass);
}
return value;
}
private Object getAbstractValue(Class extends Object> clazz, String name) {
try {
BeanConfig bc = getConfigFor(clazz);
if (bc != null) {
Class extends Object> instanceClass = bc.getAbstractProperty(name);
if (instanceClass != null) {
return instanceClass.newInstance();
}
}
throw new BeanException("Cannot instantiate property name: " + name + " from "+clazz);
} catch (Exception e) {
throw new BeanException("Cannot instantiate abstract value for "+clazz+" (field "+name+")", e);
}
}
/**
* Inject a value in a bean through reflection.
*
* @param bean
* @param fieldName
* @param value
* @param valueType
*/
protected void injectValue(final Object bean, final String fieldName, Object value, final Class extends Object> valueType) {
// first check if we have a chain of fields...
int index;
if ((index = fieldName.lastIndexOf(".")) > 0) {
if (value == null) {
// there is nothing to do here, as we don't want to create any object since the id is null...
return;
}
String chain = fieldName.substring(0, index);
String lastField = fieldName.substring(index + 1);
Object deepestBean = getDeepestBean(bean, chain, true);
injectValue(deepestBean, lastField, value, valueType);
return;
}
final Method m = InjectionUtils.findMethodToInject(bean.getClass(), fieldName, value == null ? valueType : value.getClass());
if (m == null) {
// try field...
final Field field = InjectionUtils.findFieldToInject(bean.getClass(), fieldName, value == null ? valueType : value.getClass());
if (field != null) {
// if field is a primitive (not a wrapper or void), convert a null to its default value
if (field.getType().isPrimitive() && value == null) {
value = InjectionUtils.getDefaultValueForPrimitive(field.getType());
}
try {
field.set(bean, value);
} catch (final Exception e) {
e.printStackTrace();
throw new BeanException(e);
}
} else {
// if Long and can be expressed as integer, try integer...
if (value instanceof Long) {
Long l = (Long) value;
if (l.longValue() <= Integer.MAX_VALUE && l.longValue() >= Integer.MIN_VALUE) {
injectValue(bean, fieldName, l.intValue(), Integer.class); // recursion...
return;
}
}
// Field can be a GenericType (Object). If value is null nothing will be injected..
if (value != null)
throw new BeanException("Cannot find field or method to inject: " + bean + " / " + fieldName);
}
} else {
// if field is a primitive (not a wrapper or void), convert a null to its default value
Class> paramType = m.getParameterTypes()[0];
if (paramType.isPrimitive() && value == null) {
value = InjectionUtils.getDefaultValueForPrimitive(paramType);
}
try {
m.invoke(bean, value);
} catch (final Exception e) {
e.printStackTrace();
throw new BeanException(e);
}
}
}
/**
* Some databases will sort before applying the limit (MySql), others will not (Oracle). Handle each one accordingly.
*
* Note: This base implementation does nothing.
*
* @param sb
* @param orderBy
* @param limit
* @return A string builder with the the SQL modified for the limit operation
*/
protected StringBuilder handleLimit(final StringBuilder sb, final OrderBy orderBy, final Limit limit) {
return sb;
}
/**
* Build the column/field list for a SQL SELECT statement based on the bean configuration. Very useful to create select statements.
*
* @param beanClass
* the bean class
* @return the column/field list for a select
*/
@Override
public String buildSelect(final Class extends Object> beanClass) {
return buildSelectImpl(beanClass, null, null, null, true, true);
}
@Override
public String buildSelect(final Class extends Object> beanClass, Object... properties) {
return buildSelectImpl(beanClass, null, getProperties(properties), null, true, true);
}
/**
* Build a column/field list for a SQL SELECT statement based on the bean configuration. A table prefix will be used on each field. Very useful to create select statements on multiple tables (joins).
*
* @param beanClass
* the bean class
* @param tablePrefix
* the table prefix to use before each field
* @return the column/field list for a select
*/
@Override
public String buildSelect(final Class extends Object> beanClass, final String tablePrefix) {
return buildSelectImpl(beanClass, tablePrefix, null, null, true, true);
}
@Override
public String buildSelect(final Class extends Object> beanClass, final String tablePrefix, Object... properties) {
return buildSelectImpl(beanClass, tablePrefix, getProperties(properties), null, true, true);
}
/**
* Like buildSelect but you can exclude some properties from the resulting list. Useful when you have a bean with too many properties and you just want to fetch a few.
*
* Note: The list of properties to exclude contains 'property names' and NOT database column names.
*
* @param beanClass
* the bean class
* @param minus
* a list for property names to exclude
* @return the column/field list for a select
*/
@Override
public String buildSelectMinus(final Class extends Object> beanClass, final Object... minus) {
return buildSelectImpl(beanClass, null, null, getProperties(minus), true, true);
}
/**
* Same as buildSelectMinus with support for a database table prefix that will be applied on each field.
*
* @param beanClass
* the bean class
* @param tablePrefix
* the database table prefix
* @param minus
* a list of property names to exclude
* @return the column/field list for a select
*/
@Override
public String buildSelectMinus(final Class extends Object> beanClass, final String tablePrefix, final Object... minus) {
return buildSelectImpl(beanClass, tablePrefix, null, getProperties(minus), true, true);
}
protected String buildSelectImpl(final Class extends Object> beanClass, final String tablePrefix,
final String[] properties, final String[] minus, final boolean includePK, final boolean addSuffix) {
final BeanConfig bc = getConfigFor(beanClass);
if (bc == null) {
return null;
}
final StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
final Iterator iter = bc.fields();
int count = 0;
while (iter.hasNext()) {
final DBField field = iter.next();
final String dbField = field.getDbName();
final String name = field.getName();
if (!field.isPK() || !includePK) { // always include PK
if (properties != null && !checkArray(name, properties, bc)) {
continue;
}
if (minus != null && checkArray(name, minus, bc)) {
continue;
}
}
if (count++ > 0) {
sb.append(",");
}
if (tablePrefix != null) {
sb.append(tablePrefix).append('.').append(dbField);
if (addSuffix) {
sb.append(' ');
sb.append(tablePrefix).append('_').append(dbField);
}
} else {
sb.append(dbField);
}
}
return sb.toString();
}
private boolean checkArray(final String value, final String[] array, final BeanConfig bc) {
String column = propertyToColumn(bc, value);
for (int i = 0; i < array.length; i++) {
if (propertyToColumn(bc, array[i]).equals(column)) {
return true;
}
}
return false;
}
/**
* Populate a bean (insert all its properties) from the results in a result set, based on the bean configuration.
*
* @param rset
* the result set from where to get the property values
* @param bean
* the bean to be populated
* @throws Exception
*/
@Override
public void populateBean(final ResultSet rset, final Object bean) {
populateBeanImpl(rset, bean, null, null, null, true);
}
@Override
public void populateBean(final ResultSet rset, final Object bean, Object... properties) {
populateBeanImpl(rset, bean, null, getProperties(properties), null, true);
}
/**
* Same as populateBean, but use a table prefix before fetching the values from the result set. Useful when there are multiple tables involved and you want to avoid field name clashing.
*
* @param rset
* the result set
* @param bean
* the bean to be populated
* @param tablePrefix
* the table prefix
*/
@Override
public void populateBean(final ResultSet rset, final Object bean, final String tablePrefix) {
populateBeanImpl(rset, bean, tablePrefix, null, null, true);
}
@Override
public void populateBean(final ResultSet rset, final Object bean, final String tablePrefix, Object... properties) {
populateBeanImpl(rset, bean, tablePrefix, getProperties(properties), null, true);
}
/**
* Same as populateBean, but exclude some fields when populating.
*
* @param rset
* @param bean
* @param minus
*/
@Override
public void populateBeanMinus(final ResultSet rset, final Object bean, final Object... minus) {
populateBeanImpl(rset, bean, null, null, getProperties(minus), true);
}
/**
* Same as populateBean, but exclude some fields when populating and use a table prefix in front of the field names.
*
* @param rset
* @param bean
* @param tablePrefix
* @param minus
*/
@Override
public void populateBeanMinus(final ResultSet rset, final Object bean, final String tablePrefix, final Object... minus) {
populateBeanImpl(rset, bean, tablePrefix, null, getProperties(minus), true);
}
protected void populateBeanImpl(final ResultSet rset, final Object bean, final String tablePrefix, final String[] properties, final String[] minus, boolean includePK) {
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc == null) {
throw new BeanException("Cannot find bean config: " + bean.getClass());
}
final Iterator iter = bc.fields();
final StringBuilder sbField = new StringBuilder(32);
while (iter.hasNext()) {
final DBField f = iter.next();
final String fieldName = f.getName();
if (!f.isPK() || !includePK) { // always populate PK
if (properties != null && !checkArray(fieldName, properties, bc)) {
continue;
}
if (minus != null && checkArray(fieldName, minus, bc)) {
continue;
}
}
final String dbFieldName = f.getDbName();
final DBType type = f.getType();
sbField.setLength(0);
if (tablePrefix != null) {
sbField.append(tablePrefix).append('_').append(dbFieldName);
} else {
sbField.append(dbFieldName);
}
try {
final Object value = type.getFromResultSet(rset, sbField.toString());
injectValue(bean, fieldName, value, type.getTypeClass());
} catch (Exception e) {
throw new BeanException(e);
}
}
}
/**
* Load a list of beans, but exclude some fields.
*
* @param
* @param bean
* @param minus
* @param orderBy
* @param limit
* @return A list of beans
*/
@Override
public List loadListMinus(final E bean, final OrderBy orderBy, final Limit limit, final Object... minus) {
return loadListImpl(bean, orderBy, limit, null, getProperties(minus));
}
private E checkUnique(final List list) {
if (list == null || list.size() == 0) {
return null;
} else if (list.size() > 1) {
throw new BeanException("Query returned more than one bean!");
} else {
return list.get(0);
}
}
@Override
public List loadList(final E bean, final OrderBy orderBy, final Limit limit) {
return loadListImpl(bean, orderBy, limit, null, null);
}
@Override
public List loadList(final E bean, final OrderBy orderBy, final Limit limit, Object... properties) {
return loadListImpl(bean, orderBy, limit, getProperties(properties), null);
}
private StringBuilder prepareListQuery(StringBuilder sb, BeanConfig bc, E bean, OrderBy orderBy, Limit limit, List values) {
sb.append(" FROM ").append(bc.getTableName()).append(" ");
Iterator iter = bc.fields();
int count = 0;
while (iter.hasNext()) {
final DBField field = iter.next();
final String dbField = field.getDbName();
final Method m = findMethodToGet(bean, field.getName());
boolean isNestedProperty = field.getName().contains(".");
if (m == null) {
if (!isNestedProperty) {
throw new BeanException("Cannot find method to get field from bean: " + field.getName());
} else {
continue; // nested property not set!
}
}
final Class extends Object> returnType = m.getReturnType();
final Object value = getValueFromBean(bean, field.getName(), m);
if (!isSet(value, returnType)) {
continue;
}
if (count++ > 0) {
sb.append(" AND ");
} else {
sb.append(" WHERE ");
}
sb.append(dbField).append("=?");
values.add(new Value(field, value));
}
sb.append(buildOrderBy(orderBy, bc));
sb = handleLimit(sb, orderBy, limit);
return sb;
}
private String buildOrderBy(OrderBy orderBy, BeanConfig bc) {
if (orderBy != null && !orderBy.isEmpty()) {
String orderByString = orderBy.toString();
String[] orders = orderByString.trim().split("\\s*,\\s*");
for (String order : orders) {
if (order.contains(" ")) {
order = order.substring(0, order.indexOf(" "));
}
orderByString = orderByString.replace(order, propertyToColumn(bc, order));
}
StringBuilder sb = new StringBuilder();
sb.append(" order by ").append(orderByString).append(" ");
return sb.toString();
}
return " ";
}
/**
* Returns a database column name for a bean attribute.
* @param bc - The BeanConfig
object
* @param property - A bean property
* @return The database column name found if exists, otherwise will return the
* given bean property
*/
public String propertyToColumn(BeanConfig bc, Object property) {
Iterator it = bc.fields();
String propertyName = getProperties(new Object[] {property})[0];
while (it.hasNext()) {
DBField field = it.next();
if (propertyName.equalsIgnoreCase(field.getName()))
return field.getDbName();
}
return propertyName;
}
@Override
public String propertyToColumn(Class extends Object> clazz, Object property) {
return propertyToColumn(clazz, property, null);
}
@Override
public String propertyToColumn(Class extends Object> clazz, Object property, String alias) {
BeanConfig bc = getConfigFor(clazz);
if (alias == null)
return propertyToColumn(bc, property);
return alias+"."+propertyToColumn(bc, property);
}
@Override
public String buildTableName(Class extends Object> clazz) {
return getConfigFor(clazz).getTableName();
}
@Override
public QueryBuilder buildQuery() {
return new QueryBuilder(this);
}
@Override
public int countList(Object bean) {
return countListImpl(bean, null, null);
}
private int countListImpl(final Object bean, final OrderBy orderBy, final Limit limit) {
if (limit != null && limit.intValue() == 0) {
return 0;
}
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc == null) {
throw new BeanException("Cannot find bean config: " + bean.getClass());
}
StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
sb.append("SELECT count(1)");
final List values = new LinkedList();
sb = prepareListQuery(sb, bc, bean, orderBy, limit, values);
PreparedStatement stmt = null;
ResultSet rset = null;
try {
final String sql = sb.toString();
if (DEBUG) {
System.out.println("COUNT LIST: " + sql);
}
stmt = conn.prepareStatement(sql);
final Iterator iter2 = values.iterator();
int index = 0;
while (iter2.hasNext()) {
final Value v = iter2.next();
v.field.getType().bindToStmt(stmt, ++index, v.value);
}
rset = stmt.executeQuery();
if (DEBUG_NATIVE) {
System.out.println("COUNT LIST (NATIVE): "+stmt);
}
rset.next();
return rset.getInt(1);
} catch (Exception e) {
throw new BeanException(e);
} finally {
close(stmt, rset);
}
}
private List loadListImpl(final E bean, final OrderBy orderBy, final Limit limit, final String[] properties, final String[] minus) {
if (limit != null && limit.intValue() == 0) {
return new ArrayList();
}
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc == null) {
throw new BeanException("Cannot find bean config: " + bean.getClass());
}
StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
Iterator iter = bc.fields();
sb.append("SELECT ");
int count = 0;
while (iter.hasNext()) {
final DBField field = iter.next();
final String dbField = field.getDbName();
final String name = field.getName();
if (!field.isPK()) {
if (properties != null && !checkArray(name, properties, bc)) {
continue;
}
if (minus != null && checkArray(name, minus, bc)) {
continue;
}
}
if (count++ > 0) {
sb.append(",");
}
sb.append(dbField);
}
final List values = new LinkedList();
sb = prepareListQuery(sb, bc, bean, orderBy, limit, values);
PreparedStatement stmt = null;
ResultSet rset = null;
try {
final String sql = sb.toString();
if (DEBUG) {
System.out.println("LOAD LIST: "+sql);
}
stmt = conn.prepareStatement(sql);
final Iterator iter2 = values.iterator();
int index = 0;
while (iter2.hasNext()) {
final Value v = iter2.next();
v.field.getType().bindToStmt(stmt, ++index, v.value);
}
rset = stmt.executeQuery();
if (DEBUG_NATIVE) {
System.out.println("LOAD LIST (NATIVE): " + stmt);
}
final List results = new LinkedList();
final Class extends Object> beanKlass = bean.getClass();
int total = 0;
while (rset.next()) {
iter = bc.fields();
index = 0;
final E item = (E) beanKlass.newInstance(); // not sure how to
// handle generics
// here...
while (iter.hasNext()) {
final DBField f = iter.next();
final String fieldName = f.getName();
if (!f.isPK()) {
if (properties != null && !checkArray(fieldName, properties, bc)) {
continue;
}
if (minus != null && checkArray(fieldName, minus, bc)) {
continue;
}
}
final DBType type = f.getType();
final Object value = type.getFromResultSet(rset, ++index);
injectValue(item, fieldName, value, type.getTypeClass());
}
results.add(item);
total++;
if (limit != null && limit.intValue() > 0 && total == limit.intValue()) {
return results;
}
}
return results;
} catch (Exception e) {
throw new BeanException(e);
} finally {
close(stmt, rset);
}
}
/**
* if Boolean consider TRUE to be set and FALSE to be not set.
*
* if Character, cast to integer and assume it is set if different than 0
*
* if Number consider everything different than zero to be set.
*
* Otherwise returns TRUE for anything different than null and FALSE for null.
*
* @param value
* @param returnType
* @return true if is set
*/
protected boolean isSet(final Object value, final Class extends Object> returnType) {
if (value != null) {
if (returnType.equals(boolean.class) && value instanceof Boolean) {
// if Boolean consider TRUE to be set and FALSE to be not set
// (false = default value)
final boolean b = ((Boolean) value).booleanValue();
return b;
} else if (returnType.equals(char.class) && value instanceof Character) {
// if Character, cast to int and assume set if different than
// 0...
final int c = ((Character) value).charValue();
return c != 0;
} else if (returnType.isPrimitive() && !returnType.equals(boolean.class) && !returnType.equals(char.class) && value instanceof Number) {
// if number consider everything different than zero to be
// set...
final Number n = (Number) value;
if (n.intValue() != 0) {
return true;
}
} else {
return true;
}
}
return false;
}
@Override
public int update(final Object bean, Object... forceNull) {
return update(bean, true, getProperties(forceNull));
}
@Override
public int updateAll(final Object bean) {
return update(bean, false, null);
}
private int update(final Object bean, final boolean dynUpdate, String[] nullProps) {
final Map fieldsLoaded = loaded.get(bean);
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc == null) {
throw new BeanException("Cannot find bean config: " + bean.getClass());
}
if (bc.getNumberOfFields() == 0) {
throw new BeanException("BeanConfig has zero fields: " + bc);
}
final StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
sb.append("UPDATE ").append(bc.getTableName()).append(" SET ");
Iterator iter = bc.fields();
int count = 0;
final List values = new LinkedList();
while (iter.hasNext()) {
final DBField dbField = iter.next();
if (dbField.isPK()) {
continue;
}
final DBType type = dbField.getType();
if (type instanceof AutoIncrementType) {
continue;
}
if (type instanceof AutoTimestampType) {
continue;
}
boolean isNowOnUpdate = type instanceof NowOnUpdateTimestampType || type instanceof NowOnInsertAndUpdateTimestampType;
final String fieldName = dbField.getName();
final String dbFieldName = dbField.getDbName();
if (!isNowOnUpdate) {
Method m = findMethodToGet(bean, fieldName);
Object value = null;
Class extends Object> returnType = null;
boolean isNestedProperty = fieldName.contains(".");
if (m == null && !isNestedProperty) {
throw new BeanException("Cannot find method to get field from bean: " + fieldName);
}
if (m != null) {
returnType = m.getReturnType();
value = getValueFromBean(bean, fieldName, m);
}
boolean update = false;
if (!dynUpdate) {
// if this is NOT a dynUpdate then update all properties with
// whatever value they have
update = true;
} else if (fieldsLoaded != null) {
// this is a dynUpdate, check if value is dirty, in other words,
// if it has changed since it was loaded...
final Value v = fieldsLoaded.get(fieldName);
if (v != null) {
if (value == null && v.value != null) {
update = true;
} else if (value != null && v.value == null) {
update = true;
} else if (value == null && v.value == null) {
update = false;
} else {
update = !value.equals(v.value);
}
}
} else {
// this is a dynUpdate, but bean was not previously loaded from
// the database...
// in this case only update if the property is considered to be
// SET...
update = isSet(value, returnType);
if (!update && nullProps != null) {
update = checkArray(fieldName, nullProps, bc);
}
}
if (update) {
if (count++ > 0) {
sb.append(',');
}
sb.append(dbFieldName).append("=?");
values.add(new Value(dbField, value));
}
} else {
if (count++ > 0) {
sb.append(',');
}
sb.append(dbFieldName).append("=");
String nowCommand = getCurrentTimestampCommand();
if (nowCommand == null) {
sb.append("?");
values.add(new Value(dbField, new java.util.Date()));
} else {
sb.append(nowCommand);
}
}
}
if (count == 0) {
return 0;
}
sb.append(" WHERE ");
if (!bc.hasPK()) {
throw new BeanException("Cannot update bean without a PK!");
}
iter = bc.pks();
count = 0;
while (iter.hasNext()) {
final DBField dbField = iter.next();
final String fieldName = dbField.getName();
final String dbFieldName = dbField.getDbName();
final Object value = getValueFromBean(bean, fieldName);
if (value == null) {
throw new BeanException("pk is missing: " + dbField);
} else if (value instanceof Number) {
final Number n = (Number) value;
if (n.doubleValue() <= 0) {
throw new BeanException("Number pk is missing: " + dbField);
}
}
if (count++ > 0) {
sb.append(" AND ");
}
sb.append(dbFieldName).append("=?");
values.add(new Value(dbField, value));
}
if (values.isEmpty()) {
throw new BeanException("Bean is empty: " + bean + " / " + bc);
}
if (conn == null) {
throw new BeanException("Connection is null!");
}
PreparedStatement stmt = null;
try {
if (DEBUG) {
System.out.println("UPDATE SQL: " + sb.toString());
}
dispatchBeforeUpdate(bean);
stmt = conn.prepareStatement(sb.toString());
Iterator iter2 = values.iterator();
int index = 0;
while (iter2.hasNext()) {
final Value v = iter2.next();
v.field.getType().bindToStmt(stmt, ++index, v.value);
}
final int x = stmt.executeUpdate();
if (DEBUG_NATIVE) {
System.out.println("UPDATE SQL (NATIVE): " + stmt);
}
if (x > 1) {
throw new BeanException("update modified more than one line: " + x);
}
if (x == 0) {
return 0;
}
if (fieldsLoaded != null) {
iter2 = values.iterator();
while (iter2.hasNext()) {
final Value v = iter2.next();
if (v.field.isPK()) {
continue;
}
final Value vv = fieldsLoaded.get(v.field.getName());
if (vv != null) {
vv.value = v.value;
}
}
}
dispatchAfterUpdate(bean);
return 1;
} catch (Exception e) {
throw new BeanException(e);
} finally {
close(stmt);
}
}
@Override
public E createBasicInstance(E bean) {
try {
BeanConfig bc = getConfigFor(bean.getClass());
Iterator pks = bc.pks();
DBField pk = null;
Object value = null;
E basic = (E) bean.getClass().newInstance();
while (pks.hasNext()) {
pk = pks.next();
value = getValueFromBean(bean, pk.getName());
checkPK(value, pk);
injectValue(basic, pk.getName(), value, null);
}
return basic;
}catch(Exception e) {
throw new BeanException(e);
}
}
@Override
public int save(final Object bean, Object... forceNull) {
return save(bean, true, getProperties(forceNull));
}
@Override
public int saveAll(final Object bean) {
return save(bean, false);
}
/**
* Update or insert a bean into database. It tries to update first and then insert
* @param bean Object to update or insert
* @param dynUpdate flag indicating a dynamic update
* @return A value 0 (zero) if operation was an update
,
* 1 (one) if insert
method was executed
* @see #saveAll(Object)
* @see #save(Object, Object...)
*/
protected int save(final Object bean, final boolean dynUpdate, String nullProps[]) {
try {
Object basic = createBasicInstance(bean);
if (loadUnique(basic) != null) {
update(bean, dynUpdate, nullProps);
return UPDATE;
}
}catch (BeanException e) {
// nothing to do here... try insert
}
try {
insert(bean);
return INSERT;
}catch (BeanException e) {
if (e.getCause() instanceof SQLException) {
if (((SQLException) e.getCause()).getSQLState().equals(SQLUtils.UNIQUE_KEY_VIOLATED_STATE)) {
// it means that someone already inserted a bean with the same id, so try update again
return save(bean, dynUpdate);
}
}
throw e;
}
}
private Method findMethodToGet(Object bean, String fieldName) {
Method m = null;
int index;
if ((index = fieldName.lastIndexOf(".")) > 0) {
String chain = fieldName.substring(0, index);
String lastField = fieldName.substring(index + 1);
Object deepestBean = getDeepestBean(bean, chain, false);
if (deepestBean != null) {
m = InjectionUtils.findMethodToGet(deepestBean.getClass(), lastField);
}
} else {
m = InjectionUtils.findMethodToGet(bean.getClass(), fieldName);
}
return m;
}
protected class QueryAndValues {
public QueryAndValues(StringBuilder sb, List values) {
this.sb = sb;
this.values = values;
}
public StringBuilder sb;
public List values;
}
protected QueryAndValues prepareInsertQuery(Object bean) {
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc == null) {
throw new BeanException("Cannot find bean config: " + bean.getClass());
}
if (bc.getNumberOfFields() == 0) {
throw new BeanException("BeanConfig has zero fields: " + bc);
}
final StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
sb.append("INSERT INTO ").append(bc.getTableName()).append("(");
Iterator iter = bc.pks();
int count = 0;
final List values = new LinkedList();
while (iter.hasNext()) {
final DBField dbField = iter.next();
final String fieldName = dbField.getName();
final String dbFieldName = dbField.getDbName();
final DBType type = dbField.getType();
if (type instanceof AutoIncrementType) {
continue;
}
if (type instanceof AutoTimestampType) {
continue;
}
if (type instanceof NowOnUpdateTimestampType) {
continue;
}
final Object value = getValueFromBean(bean, fieldName);
if (count++ > 0) {
sb.append(',');
}
sb.append(dbFieldName);
values.add(new Value(dbField, value));
}
iter = bc.fields();
while (iter.hasNext()) {
final DBField dbField = iter.next();
if (dbField.isPK()) {
continue;
}
final String fieldName = dbField.getName();
final String dbFieldName = dbField.getDbName();
final DBType type = dbField.getType();
if (type instanceof AutoIncrementType) {
continue;
}
if (type instanceof AutoTimestampType) {
continue;
}
if (type instanceof NowOnUpdateTimestampType) {
continue;
}
boolean isNowOnInsert = type instanceof NowOnInsertTimestampType || type instanceof NowOnInsertAndUpdateTimestampType;
if (!isNowOnInsert) {
Object value = getValueFromBean(bean, fieldName);
if (count++ > 0) {
sb.append(',');
}
sb.append(dbFieldName);
values.add(new Value(dbField, value));
} else {
if (count++ > 0) {
sb.append(',');
}
sb.append(dbFieldName);
String cmd = getCurrentTimestampCommand();
if (cmd == null) {
values.add(new Value(dbField, new java.util.Date()));
} else {
values.add(new Value(dbField, true));
}
}
}
if (count == 0) {
throw new BeanException("There is nothing to insert!");
}
sb.append(") VALUES(");
final Iterator valuesIter = values.iterator();
int i = 0;
while (valuesIter.hasNext()) {
final Value v = valuesIter.next();
if (i > 0) {
sb.append(',');
}
if (v.isSysdate) {
sb.append(getCurrentTimestampCommand());
} else {
sb.append('?');
}
i++;
}
sb.append(')');
if (values.isEmpty()) {
throw new BeanException("Bean is empty: " + bean + " / " + bc);
}
return new QueryAndValues(sb, values);
}
protected Map bindToInsertStatement(PreparedStatement stmt, List values) {
final Iterator iter2 = values.iterator();
int index = 0;
final Map fieldsLoaded = new HashMap();
while (iter2.hasNext()) {
final Value v = iter2.next();
if (v.isSysdate && getCurrentTimestampCommand() != null) {
continue;
}
try {
v.field.getType().bindToStmt(stmt, ++index, v.value);
} catch (Exception e) {
throw new BeanException(e);
}
fieldsLoaded.put(v.field.getName(), v);
}
return fieldsLoaded;
}
@Override
public void insert(final Object bean) {
QueryAndValues qav = prepareInsertQuery(bean);
StringBuilder sb = qav.sb;
List values = qav.values;
if (conn == null) {
throw new BeanException("Connection is null!");
}
PreparedStatement stmt = null;
try {
if (DEBUG) {
System.out.println("INSERT SQL: " + sb.toString());
}
stmt = conn.prepareStatement(sb.toString());
Map fieldsLoaded = bindToInsertStatement(stmt, values);
dispatchBeforeInsert(bean);
final int x = stmt.executeUpdate();
if (DEBUG_NATIVE) {
System.out.println("INSERT SQL (NATIVE): " + stmt);
}
if (x > 1) {
throw new BeanException("insert modified more than one line: " + x);
}
if (x == 0) {
throw new BeanException("Nothing was inserted! Insert returned 0 rows!");
}
loaded.put(bean, fieldsLoaded);
} catch (Exception e) {
throw new BeanException(e);
} finally {
close(stmt);
}
}
@Override
public boolean delete(final Object bean) {
final BeanConfig bc = getConfigFor(bean.getClass());
if (bc.getNumberOfFields() == 0) {
throw new BeanException("BeanConfig has zero fields: " + bc);
}
final StringBuilder sb = new StringBuilder(32 * bc.getNumberOfFields());
sb.append("DELETE FROM ").append(bc.getTableName()).append(" WHERE ");
if (!bc.hasPK()) {
throw new BeanException("Cannot delete bean without a PK!");
}
final Iterator iter = bc.pks();
final List values = new LinkedList();
int count = 0;
while (iter.hasNext()) {
final DBField dbField = iter.next();
final String fieldName = dbField.getName();
final String dbFieldName = dbField.getDbName();
final Object value = getValueFromBean(bean, fieldName);
if (value == null) {
throw new BeanException("pk is missing: " + dbField);
} else if (value instanceof Number) {
final Number n = (Number) value;
if (n.doubleValue() <= 0) {
throw new BeanException("Number pk is missing: " + dbField);
}
}
if (count++ > 0) {
sb.append(" AND ");
}
sb.append(dbFieldName).append("=?");
values.add(new Value(dbField, value));
}
if (values.isEmpty()) {
throw new BeanException("Bean is empty: " + bean + " / " + bc);
}
if (conn == null) {
throw new BeanException("Connection is null!");
}
PreparedStatement stmt = null;
try {
if (DEBUG) {
System.out.println("DELETE SQL: " + sb.toString());
}
stmt = conn.prepareStatement(sb.toString());
final Iterator iter2 = values.iterator();
int index = 0;
while (iter2.hasNext()) {
final Value v = iter2.next();
v.field.getType().bindToStmt(stmt, ++index, v.value);
}
dispatchBeforeDelete(bean);
final int x = stmt.executeUpdate();
if (DEBUG_NATIVE) {
System.out.println("DELETE SQL (NATIVE): " + stmt);
}
if (x > 1) {
throw new BeanException("delete modified more than one line: " + x);
}
if (x == 0) {
return false;
}
loaded.remove(bean);
dispatchAfterDelete(bean);
return true;
} catch (Exception e) {
throw new BeanException(e);
} finally {
close(stmt);
}
}
@Override
public List loadList(final E bean) {
return loadListImpl(bean, null, null, null, null);
}
@Override
public List loadList(final E bean, Object... properties) {
return loadListImpl(bean, null, null, getProperties(properties), null);
}
@Override
public E loadUnique(E bean) {
return loadUniqueImpl(bean, null, null);
}
@Override
public E loadUnique(E bean, Object... properties) {
return loadUniqueImpl(bean, getProperties(properties), null);
}
@Override
public E loadUniqueMinus(E bean, Object... minus) {
return loadUniqueImpl(bean, null, getProperties(minus));
}
protected E loadUniqueImpl(final E bean, String[] properties, String[] minus) {
E o = checkUnique(loadListImpl(bean, null, new Limit(2), properties, minus));
if (o != null) {
load(o); // load twice to attach to session so dynamic update is by default!
}
return o;
}
@Override
public List loadList(final E bean, final OrderBy orderBy) {
return loadListImpl(bean, orderBy, null, null, null);
}
@Override
public List loadList(final E bean, final OrderBy orderBy, Object... properties) {
return loadListImpl(bean, orderBy, null, getProperties(properties), null);
}
@Override
public List loadList(final E bean, final Limit limit) {
return loadList(bean, null, limit);
}
@Override
public List loadList(final E bean, final Limit limit, Object... properties) {
return loadListImpl(bean, null, limit, getProperties(properties), null);
}
/**
* Load a list of beans, but exclude some fields. Useful when the bean has too many properties and you don't want to fetch everything from the database.
*
* @param
* @param bean
* @param minus
* @return A list of beans
*/
@Override
public List loadListMinus(final E bean, final Object... minus) {
return loadListMinus(bean, null, null, minus);
}
/**
* Load a list of beans, but exclude some fields. Useful when the bean has too many properties and you don't want to fetch everything from the database.
*
* @param
* @param bean
* @param minus
* @param orderBy
* @return A list of beans
*/
@Override
public List loadListMinus(final E bean, final OrderBy orderBy, final Object... minus) {
return loadListMinus(bean, orderBy, null, minus);
}
/**
* Load a list of beans, but exclude some fields. Useful when the bean has too many properties and you don't want to fetch everything from the database.
*
* @param
* @param bean
* @param minus
* @param limit
* @return A list of beans
*/
@Override
public List loadListMinus(final E bean, final Limit limit, final Object... minus) {
return loadListMinus(bean, null, limit, minus);
}
/**
* Each dialect can override this to return the database column type it supports other than the ANSI standard.
*
* @param dbType
* @return The string representation of this database type to be used with create table statement
*/
protected String getDatabaseType(DBType> dbType) {
return dbType.getAnsiType();
}
/**
* Each dialect can override this to return true if the VARCHAR type supports unlimited size
* @return true if database supports VARCHAR with no limit, false otherwise
*/
protected boolean isVarcharUnlimitedSupported() {
return false;
}
@Override
public void createTable(Class extends Object> beanKlass) {
BeanConfig bc = getConfigFor(beanKlass);
if (bc == null) {
throw new BeanException("Cannot find bean config: " + beanKlass);
}
if (bc.getNumberOfFields() == 0) {
throw new BeanException("Cannot create table with zero columns: " + beanKlass);
}
StringBuilder sb = new StringBuilder(1024);
sb.append("create table ").append(bc.getTableName()).append(" (");
Iterator iter = bc.fields();
int count = 0;
while (iter.hasNext()) {
DBField dbField = iter.next();
DBType> dbType = dbField.getType();
if (count++ > 0) {
sb.append(", ");
}
String dbTypeStr = getDatabaseType(dbType);
if (dbTypeStr == null)
throw new BeanException("Invalid ANSI type for column '"+
dbField.getDbName()+"' in table '"+bc.getTableName()+"'. Maybe you're using a GenericType.");
sb.append(dbField.getDbName()).append(" ").append(dbTypeStr);
if (dbType instanceof SizedType) {
int size = ((SizedType) dbType).getSize();
if (size <= 0 && !isVarcharUnlimitedSupported()) {
// no limit is not supported, so get the default size..
size = SizedType.DEFAULT_SIZE;
}
if (size > 0)
sb.append("(").append(size).append(")");
}
if (dbType.canBeNull() == false || dbField.isPK()) {
sb.append(" NOT NULL");
}
}
sb.append(")");
if (DEBUG) {
System.out.println("CREATE TABLE SQL: " + sb.toString());
}
PreparedStatement stmt = null;
boolean autoCommit = false;
try {
autoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
stmt = conn.prepareStatement(sb.toString());
stmt.executeUpdate();
if (DEBUG_NATIVE) {
System.out.println("CREATE TABLE SQL (NATIVE): " + stmt);
}
close(stmt);
String pkConstraintQuery = createPKConstraintQuery(bc.getTableName(), bc.pks());
if (DEBUG) {
System.out.println("PK CONSTRAINT QUERY: "+pkConstraintQuery);
}
stmt = conn.prepareStatement(pkConstraintQuery);
stmt.executeUpdate();
if (DEBUG_NATIVE) {
System.out.println("PK CONSTRAINT QUERY (NATIVE): " + stmt);
}
if (autoCommit)
conn.commit();
} catch (Exception e) {
if (autoCommit) {
try {
conn.rollback();
conn.setAutoCommit(true);
}catch (Exception e2) {
throw new BeanException(e2);
}
}
throw new BeanException(e);
} finally {
if (autoCommit) {
try {
conn.setAutoCommit(true);
}catch (Exception e) {
throw new BeanException(e);
}
}
close(stmt);
}
}
@Override
public void createTables() {
Set all = beanManager.getBeanConfigs();
for (BeanConfig bc : all) {
createTable(bc.getBeanClass());
}
}
@Override
public void dropTable(Class extends Object> beanKlass) {
StringBuilder sb = new StringBuilder("DROP TABLE ");
String tableName = buildTableName(beanKlass);
sb.append(tableName);
if (DEBUG) {
System.out.println("DROP TABLE QUERY: "+sb.toString());
}
PreparedStatement ppst = null;
try {
ppst = SQLUtils.prepare(conn, sb.toString());
ppst.executeUpdate();
if (DEBUG_NATIVE) {
System.out.println("DROP TABLE QUERY (NATIVE): "+ppst);
}
}catch (SQLException e) {
throw new BeanException("Unable to drop table '"+tableName+"'", e);
}finally {
SQLUtils.close(ppst);
}
}
/**
* Create a SQL query to add the primary key constraint
* @param table - The table name
* @param pks - An iterator of all primary key fields that will be added to the table
* @return A String containing the resulting alter table constraint query
*/
protected String createPKConstraintQuery(String table, Iterator pks) {
StringBuilder sb = new StringBuilder("alter table ");
sb.append(table);
sb.append(" add primary key (");
if (pks.hasNext())
sb.append(pks.next().getDbName());
while (pks.hasNext()) {
DBField dbField = pks.next();
sb.append(", ").append(dbField.getDbName());
}
return sb.append(")").toString();
}
private int getSize(DBType> dbType) {
if (dbType instanceof SizedType) {
SizedType st = (SizedType) dbType;
return st.getSize();
}
throw new IllegalStateException("Cannot get size from type: " + dbType);
}
public BeanConfig getConfigFor(Class extends Object> clazz) {
return beanManager.getBeanConfig(clazz);
}
@Override
public void addTrigger(TriggerListener trigger) {
dispatcher.addTrigger(trigger);
}
@Override
public void removeTrigger(TriggerListener trigger) {
dispatcher.removeTrigger(trigger);
}
protected void dispatchBeforeInsert(Object bean) {
dispatchTrigger(Type.BEFORE_INSERT, bean);
}
protected void dispatchAfterInsert(Object bean) {
dispatchTrigger(Type.AFTER_INSERT, bean);
}
protected void dispatchBeforeUpdate(Object bean) {
dispatchTrigger(Type.BEFORE_UPDATE, bean);
}
protected void dispatchAfterUpdate(Object bean) {
dispatchTrigger(Type.AFTER_UPDATE, bean);
}
protected void dispatchBeforeDelete(Object bean) {
dispatchTrigger(Type.BEFORE_DELETE, bean);
}
protected void dispatchAfterDelete(Object bean) {
dispatchTrigger(Type.AFTER_DELETE, bean);
}
/**
* Dispatch all triggers from actual BeanSession
and respective BeanConfig
.
* This method is called when insert , update or delete operation occurs.
* @param type - TriggerType indicating what trigger event will be dispatched
* @param bean - Bean that will be set into TriggerEvent object
*/
protected void dispatchTrigger(Type type, Object bean) {
TriggerEvent evt = new TriggerEvent(this, bean);
dispatcher.dispatch(type, evt);
getConfigFor(bean.getClass()).getDispatcher().dispatch(type, evt);
}
protected class Value {
public Object value;
public DBField field;
public boolean isSysdate;
private Value(final DBField field, Object value, final boolean isSysdate) {
this.field = field;
this.value = value;
this.isSysdate = isSysdate;
}
public Value(final DBField field, final Object value) {
this(field, value, false);
}
public Value(final DBField field, final boolean isSysdate) {
this(field, null, isSysdate);
}
}
static void close(PreparedStatement stmt) {
SQLUtils.close(stmt);
}
static void close(PreparedStatement stmt, ResultSet rset) {
SQLUtils.close(rset, stmt);
}
@Override
public TableAlias createTableAlias(Class extends E> beanClass) {
return new TableAlias(this, beanManager.getBeanConfig(beanClass), beanClass);
}
@Override
public TableAlias createTableAlias(Class extends E> beanClass, String prefix) {
return new TableAlias(this, beanManager.getBeanConfig(beanClass), beanClass, prefix);
}
}