
de.tsl2.nano.service.util.ServiceUtil Maven / Gradle / Ivy
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Thomas Schneider
* created on: Apr 13, 2010
*
* Copyright: (c) Thomas Schneider 2010, all rights reserved
*/
package de.tsl2.nano.service.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import de.tsl2.nano.bean.IAttributeDef;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.cls.BeanAttribute;
import de.tsl2.nano.core.cls.BeanClass;
import de.tsl2.nano.core.cls.PrimitiveUtil;
import de.tsl2.nano.core.log.LogFactory;
import de.tsl2.nano.core.util.StringUtil;
/**
* some utility functions to be used by services.
*
* @author Thomas Schneider
* @version $Revision$
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class ServiceUtil {
static final String OP_EQ = " = ";
static final String OP_LT = " < ";
static final String OP_GT = " > ";
static final String OP_LE = " <= ";
static final String OP_GE = " >= ";
public static final String OP_LIKE = " like ";
public static final String CLAUSE_SELECT = "select ";
public static final String CLAUSE_WHERE = " where ";
public static final String CLAUSE_AND = " and ";
public static final String CLAUSE_OR = " or ";
public static final String CLAUSE_NOT = " and not ";
static final String BRACKET_OPEN = " ( ";
static final String BRACKET_CLOSE = " ) ";
/** sql name of first sql result substitute (see {@link #createStatement(Class)} */
public static final String SUBST_RESULTBEAN = "t";
static final String VALUE_PH = "?";
protected static final long MINTIME = -62167395600000l /* 01.01.0000 */;
protected static final long MAXTIME = 32535126000000l /* 31.12.3000 */;
protected static final String STR_MIN_VALUE = "MIN_VALUE";
protected static final String STR_MAX_VALUE = "MAX_VALUE";
private static final Log LOG = LogFactory.getLog(ServiceUtil.class);
/**
* @param beanType
* @return base select query
*/
public static StringBuffer createStatement(Class> beanType) {
return createStatement(beanType, SUBST_RESULTBEAN);
}
/**
* @param beanType
* @return base select query
*/
public static StringBuffer createStatement(Class> beanType, String substName) {
substName = substName.endsWith(".") ? substName.substring(0, substName.length() - 1) : substName;
return new StringBuffer("select " + substName
+ " from "
+ BeanClass.getName(beanType)
+ " "
+ substName
+ " \n");
}
/** creates an jpa-ql to find all beans with same attributes (only single value attributes!) as exampleBean */
public static Collection> createExampleStatement(StringBuffer qStr,
Object exampleBean,
boolean useLike,
boolean caseInsensitive) {
if (qStr.length() == 0) {
qStr.append(createStatement(exampleBean.getClass()));
}
final Collection parameter = new LinkedList();
qStr = addAndConditions(qStr, exampleBean, useLike ? OP_LIKE : OP_EQ, parameter, caseInsensitive);
LOG.debug(getLogInfo(qStr, parameter));
return parameter;
}
/**
* creates a jpa-ql statement to find all beans, having properties between firstBean and secondBean.
*
* @param beantype
* @param qStr string buffer to fill with new statement. if qStr is empty the select statement result will hold all
* fields of the bean. if not, it has to be filled until the where clause.
* @param firstBean minimum bean
* @param secondBean maximum bean
* @param caseInsensitive whether to search strings case insensitive
* @return parameter list of created statement
*/
public static Collection> createBetweenStatement(StringBuffer qStr,
T firstBean,
T secondBean,
boolean caseInsensitive) {
prepareStringValuesForBetween(firstBean, secondBean);
if (qStr.length() == 0) {
qStr.append(createStatement(firstBean.getClass()));
}
final Collection parameter = new LinkedList();
addBetweenConditions(qStr, firstBean, secondBean, parameter, caseInsensitive);
LOG.debug(getLogInfo(qStr, parameter));
return parameter;
}
public static StringBuffer addAndConditions(StringBuffer qStr,
Object valueBean,
String operator,
Collection parameter,
boolean caseInsensitive) {
return addAndConditions(qStr, null, null, valueBean, operator, parameter, caseInsensitive);
}
public static StringBuffer addAndConditions(StringBuffer qStr,
String attrPrefix,
Object valueBean,
String operator,
Collection parameter,
boolean caseInsensitive) {
return addAndConditions(qStr, attrPrefix, null, valueBean, operator, parameter, caseInsensitive);
}
/**
* creates an ejb-ql query using the valueBean and its attribute-names to add 'and' conditions to the where-clause.
* it is intelligent to find the right syntax for different attribute types. if an attribute value holds an '*', the
* operator {@linkplain #OP_LIKE} will be used instead of the given operator.
*
* @param qStr query to fill
* @param attrPrefix (optional) needed on recursive entity attribute calls
* @param valueBean value holding bean
* @param operator operator to be used on and conditions (see {@link #OP_EQ} etc.)
* @param parameter statement parameter list to be filled by this call
* @param caseInsensitive if true, strings will be search case insensitive --> performance will be lower!
* @return oql query statement
*/
public static StringBuffer addAndConditions(StringBuffer qStr,
String attrPrefix,
String and_cond,
Object valueBean,
String operator,
Collection parameter,
boolean caseInsensitive) {
String bracket_close = "";
if (and_cond == null) {
and_cond = CLAUSE_AND;
}
if (!qStr.toString().contains(CLAUSE_WHERE)) {
and_cond = CLAUSE_WHERE;
}
attrPrefix = attrPrefix == null ? SUBST_RESULTBEAN + "." : attrPrefix;
final Class> clazz = BeanClass.getDefiningClass(valueBean.getClass());
final BeanClass bclazz = BeanClass.getBeanClass(clazz);
final Collection attributes = bclazz.getSingleValueAttributes();
Object value;
for (final BeanAttribute beanAttribute : attributes) {
final IAttributeDef attributeDef = BeanContainerUtil.getAttributeDefinitions(beanAttribute);
if (attributeDef != null && !attributeDef.isTransient()) {//only attributes with column-defs will be used!
final String name = beanAttribute.getName();//getColumnName(beanAttribute);
final boolean isString = CharSequence.class.isAssignableFrom(beanAttribute.getType());
final String varName = caseInsensitive && isString ? "LOWER(" + attrPrefix + name + ") " : attrPrefix + name + " ";
value = beanAttribute.getValue(valueBean);
if (value == null) {
continue;
}
//workaround on primitives having always a value: we ignore the default values
if (beanAttribute.getType().isPrimitive() && PrimitiveUtil.isDefaultValue(beanAttribute.getType(), value))
continue;
//recursive entity-attributes on persistent objects
if (BeanContainerUtil.isPersistable(beanAttribute.getType()) && getId(value) == null) {
addAndConditions(qStr, attrPrefix + name + ".", value, operator, parameter, caseInsensitive);
//the relations can have only null values, so that no where/and clause may be added
if (qStr.toString().contains(CLAUSE_WHERE)) {
qStr.append("\n");
and_cond = CLAUSE_AND;
}
continue;
}
//on manyToOne mappings use the foreignkey column
final boolean isManyToOne = false;
// if (!BeanUtil.isStandardType(value.getClass())) {
// Collection foreignIdAttributes = new BeanClass(value.getClass()).findAttributes(Id.class);
// if (foreignIdAttributes.size() > 0) {
// BeanAttribute foreignKey = foreignIdAttributes.iterator().next();
// value = foreignKey.getValue(value);
// name = name + "." + foreignKey.getName();
// isManyToOne = true;
// }
// }
if (!isManyToOne && value instanceof String) {
String strValue = caseInsensitive ? String.valueOf(value).toLowerCase() : String.valueOf(value);
final boolean isLikeValue = strValue.endsWith("*");
if (isLikeValue) {
strValue = strValue.replace('*', '%');
} else {
if (operator.equals(OP_GE) || operator.equals(OP_GT)) {
if (attributeDef.length() > 0) {
strValue = StringUtil.fixString(strValue, attributeDef.length(), '0', true);
}
/*
* the between mechanism (e.g.: between abc000 and abczzz) doesn't respect the full match!
* so we have to add an and-condition (with brackets!) to the full match with EQUAL.
*/
qStr.append(and_cond + BRACKET_OPEN + varName + OP_EQ + VALUE_PH + (parameter.size()+1));
and_cond = CLAUSE_OR;
parameter.add(caseInsensitive ? ((String) value).toLowerCase() : (String) value);
} else if (operator.equals(OP_LE) || operator.equals(OP_LT)) {
if (attributeDef.length() > 0) {
strValue = StringUtil.fixString(strValue, attributeDef.length(), 'z', true);
}
bracket_close = BRACKET_CLOSE;
}
}
qStr.append(and_cond + varName + (isLikeValue ? OP_LIKE : operator) + VALUE_PH + (parameter.size()+1) + bracket_close);
value = strValue;
} else if (isManyToOne && value instanceof String) {
qStr.append(and_cond + attrPrefix + name + OP_EQ + VALUE_PH + (parameter.size()+1));
} else {// if no string, like is not possible
final String op = OP_LIKE.equals(operator) ? OP_GE : operator;
qStr.append(and_cond + attrPrefix + name + op + VALUE_PH + (parameter.size()+1));
}
parameter.add(value);
and_cond = CLAUSE_AND;
}
}
return qStr;
}
/**
* delegates to {@link #addBetweenConditions(StringBuffer, String, Object, Object, Collection, boolean)}.
*/
public static StringBuffer addBetweenConditions(StringBuffer qStr,
Object fromBean,
Object toBean,
Collection parameter,
boolean caseInsensitive) {
return addBetweenConditions(qStr, null, fromBean, toBean, parameter, caseInsensitive);
}
public static StringBuffer addBetweenConditions(StringBuffer qStr,
String attrPrefix,
Object fromBean,
Object toBean,
Collection parameter,
boolean caseInsensitive) {
return addBetweenConditions(qStr, attrPrefix, null, fromBean, toBean, parameter, caseInsensitive);
}
/**
* creates an ejb-ql query using the valueBean and its attribute-names to add 'and' conditions to the where-clause.
* it is intelligent to find the right syntax for different attribute types. if an attribute value holds an '*', the
* operator {@linkplain #OP_LIKE} will be used instead of the given operator.
*
* @param qStr select query to fill
* @param attrPrefix (optional) needed on recursive calls to define the full attribute path
* @param fromBean value holding bean
* @param toBean value holding bean
* @param parameter statement parameter list to be filled by this call
* @return oql query statement
*/
public static StringBuffer addBetweenConditions(StringBuffer qStr,
String attrPrefix,
String and_cond,
Object fromBean,
Object toBean,
Collection parameter,
boolean caseInsensitive) {
String bracket_open = "", bracket_close = "";
if (and_cond == null) {
and_cond = CLAUSE_AND;
}
if (!qStr.toString().contains(CLAUSE_WHERE)) {
and_cond = CLAUSE_WHERE;
}
attrPrefix = attrPrefix == null ? SUBST_RESULTBEAN + "." : attrPrefix;
final Class> clazz = fromBean.getClass();
final BeanClass bclazz = BeanClass.getBeanClass(clazz);
final Collection attributes = bclazz.getSingleValueAttributes();
Object fromValue, toValue;
String strValue;
for (final BeanAttribute beanAttribute : attributes) {
final IAttributeDef attributeDef = BeanContainerUtil.getAttributeDefinitions(beanAttribute);
if (attributeDef != null && !attributeDef.isTransient()) {//only attributes with column-defs will be used!
final String name = beanAttribute.getName();//getColumnName(beanAttribute);
final boolean isString = CharSequence.class.isAssignableFrom(beanAttribute.getType());
final String varName = caseInsensitive && isString ? "LOWER(" + attrPrefix + name + ") " : attrPrefix + name + " ";
fromValue = fromBean != null ? beanAttribute.getValue(fromBean) : null;
toValue = toBean != null ? beanAttribute.getValue(toBean) : null;
if (fromValue == null && toValue == null) {
continue;
}
//recursive entity-attributes on transient objects
if (BeanContainerUtil.isPersistable(beanAttribute.getType())
&& ((fromValue != null && getId(fromValue) == null) || (toValue != null && getId(toValue) == null))) {
addBetweenConditions(qStr, attrPrefix + name + ".", fromValue, toValue, parameter, caseInsensitive);
qStr.append("\n");
and_cond = CLAUSE_AND;
continue;
}
/*
* on different from, to values, we create a between
* strings will be different on using the filling mechanism (e.g.: sch0000 to schzzzz)
*/
if (fromValue == null || !fromValue.equals(toValue) || fromValue instanceof String) {
bracket_open = BRACKET_OPEN;
/*
* only for strings:
* the between mechanism (e.g.: between abc000 and abczzz) doesn't respect the full match!
* so we have to add an and-condition (with brackets!) to the full match with EQUAL.
*/
if (fromValue instanceof String) {
strValue = fromValue != null ? (caseInsensitive ? fromValue.toString().toLowerCase()
: fromValue.toString()) : "";
if (attributeDef.length() > 0) {
strValue = StringUtil.fixString(strValue, attributeDef.length(), '0', true);
}
qStr.append(and_cond + bracket_open + varName + OP_EQ + VALUE_PH + (parameter.size()+1));
and_cond = CLAUSE_OR;
bracket_open = "";
parameter.add(caseInsensitive ? ((String) fromValue).toLowerCase() : (String) fromValue);
fromValue = strValue;
}
/*
* now, the standard between: start with greater equal
*/
if (fromValue != null) {
qStr.append(and_cond + bracket_open + varName + OP_GE + VALUE_PH + (parameter.size()+1) + bracket_close);
parameter.add(fromValue);
and_cond = CLAUSE_AND;
bracket_close = BRACKET_CLOSE;
} else {
bracket_close = "";
}
/*
* the end: lower equal
*/
if (toValue instanceof String) {
strValue = toValue != null ? (caseInsensitive ? toValue.toString().toLowerCase()
: toValue.toString()) : "";
if (attributeDef.length() > 0) {
strValue = StringUtil.fixString(strValue, attributeDef.length(), 'z', true);
}
toValue = strValue;
}
if (toValue != null) {
qStr.append(and_cond + varName + OP_LE + VALUE_PH + (parameter.size()+1) + bracket_close);
parameter.add(toValue);
} else {
qStr.append(bracket_close);
}
} else {// no range: we create a simple equals
if (toValue != null) {
qStr.append(and_cond + attrPrefix + name + OP_EQ + VALUE_PH + (parameter.size()+1));
parameter.add(toValue);
}
}
and_cond = CLAUSE_AND;
bracket_close = "";
}
}
return qStr;
}
/**
* delegates to {@link #addMemberExpression(StringBuffer, String, Object, Class, String)} using
* {@link #SUBST_RESULTBEAN}.
*/
public static StringBuffer addMemberExpression(StringBuffer qStr,
H holder,
Class beanType,
String attributeName) {
return addMemberExpression(qStr, SUBST_RESULTBEAN, 1, holder, beanType, attributeName);
}
/**
* find all beans of type beanType beeing members of holder. useful if your beanType has no access to the holder.
*
*
*
* f.e.:
* Parent (1) <-- (*) Child
* ==> but you want to get the parents children!
* will result in:
* select t from Child t, Parent t1
* where t1.ID = holder.ID
* and t member of t1.{attributeName}
*
*
* @param holder type
* @param member type
* @param beanType member type to be collected
* @param holder holder instance to get the members of (without direct access!)
* @param attributeName
* @return members of holder (member given by attributeName)
*/
public static StringBuffer addMemberExpression(StringBuffer qStr,
String substName,
int index,
H holder,
Class beanType,
String attributeName) {
//the select must be prepared up to the first 'from'-clause-entry. mostly the string will end with a newline --> we delete that.
qStr.deleteCharAt(qStr.length() - 1);
final String idAttribute = getIdName(holder);
String tm = "tm" + index;
qStr.append(", " + holder.getClass().getSimpleName()
+ " "
+ tm
+ "\n where ("
+ tm
+ "."
+ idAttribute
+ " = ?X and "
+ substName
+ " member of "
+ tm
+ "."
+ attributeName
+ ")");
return qStr;
}
/**
* delegates to {@link #addHolderExpression(StringBuffer, String, Object, Class, String)} using
* {@link #SUBST_RESULTBEAN}.
*/
public static StringBuffer addHolderExpression(StringBuffer qStr,
T member,
Class holderType,
String attributeName) {
return addHolderExpression(qStr, SUBST_RESULTBEAN, 1, member, holderType, attributeName);
}
/**
* find all holders of the given member instance. useful if your member has no access to the holder. on composites
* and aggregations you will get a collection holding only one instance.
*
*
*
* f.e.:
* Parent (1) --> (*) Child
* ==> but you want to get a childs parent!
* will result in:
* select t from Child t, Parent t1
* where t.ID = member.ID
* and t member of t1.{attributeName}
*
*
* @param holder type
* @param member type
* @param beanType member type to be collected
* @param holder holder instance to get the members of (without direct access!)
* @param attributeName
* @return members of holder (member given by attributeName)
*/
public static StringBuffer addHolderExpression(StringBuffer qStr,
String substName,
int index,
T member,
Class holderType,
String attributeName) {
//the select must be prepared up to the first 'from'-clause-entry. mostly the string will end with a newline --> we delete that.
qStr.deleteCharAt(qStr.length() - 1);
final String idAttribute = getIdName(member);
String th = "th" + index;
qStr.append(", " + member.getClass().getSimpleName()
+ " "
+ th
+ "\n where ("
+ th
+ "."
+ idAttribute
+ " = ?X and "
+ th
+ " member of "
+ substName
+ "."
+ attributeName
+ ")");
return qStr;
}
/**
* addInSelection
*
* @param qStr current select
* @param substName table subst name
* @param attribute attribute name to have value in selection
* @param selection value selection for attribute
* @return extended select
*/
public static StringBuffer addInSelection(StringBuffer qStr,
String clause,
String substName,
String attribute,
Collection> selection) {
return qStr.append(" " + clause + " " + substName + "." + attribute + " in (?X)");
}
/**
* tries to find the method with id-annotation. if not existing, return null. it is a generic method with poor
* performance.
*
* @param bean bean instance, holding an id.
* @return id of bean or null.
*/
public static Object getId(Object bean) {
LOG.debug("evaluation bean-id for :" + bean);
final Method m = getIdMethod(bean);
if (m != null) {
try {
LOG.debug("invoking bean-id on : " + m);
return m.invoke(bean, new Object[0]);
} catch (final Exception e) {
ManagedException.forward(e);
}
}
//on a field?
final Field f = getIdField(bean);
if (f != null) {
try {
LOG.debug("invoking bean-id on : " + f);
if (f.isAccessible()) {
return f.get(bean);
} else {
final BeanAttribute readAccess = BeanAttribute.getBeanAttribute(bean.getClass(), f.getName());
return readAccess.getValue(bean);
}
} catch (final Exception e) {
LOG.error("The @Id field '" + f.getName() + " ' is not accessible!!!");
ManagedException.forward(e);
}
}
return null;
}
public static Method getIdMethod(Object bean) {
final Method[] methods = bean.getClass().getMethods();
for (final Method m : methods) {
if (m.isAnnotationPresent(javax.persistence.Id.class)) {
LOG.debug("invoking bean-id on : " + m);
return m;
} else if (m.isAnnotationPresent(EmbeddedId.class)) {
LOG.debug("invoking bean-embedded-id on : " + m);
return m;
}
}
return null;
}
public static Field getIdField(Object bean) {
final Field[] fields = bean.getClass().getDeclaredFields();
for (final Field f : fields) {
if (f.isAnnotationPresent(javax.persistence.Id.class)) {
return f;
} else if (f.isAnnotationPresent(EmbeddedId.class)) {
return f;
}
}
/*
* if a super class defines the id field, we will find it now - or null
*/
Class superClass = bean.getClass().getSuperclass();
return superClass != null ? getSuperIdField(superClass) : null;
}
public static Field getSuperIdField(Class clazz) {
final Field[] fields = clazz.getDeclaredFields();
for (final Field f : fields) {
if (f.isAnnotationPresent(javax.persistence.Id.class)) {
return f;
} else if (f.isAnnotationPresent(EmbeddedId.class)) {
return f;
}
}
Class superClass = clazz.getSuperclass();
return superClass != null ? getSuperIdField(superClass) : null;
}
public static String getIdName(Object bean) {
final BeanClass bc = BeanClass.getBeanClass(bean.getClass());
Collection attributes = bc.findAttributes(Id.class);
if (attributes.size() > 0) {
return attributes.iterator().next().getName();
} else {
attributes = bc.findAttributes(EmbeddedId.class);
if (attributes.size() > 0) {
return attributes.iterator().next().getName();
} else {
return null;
}
}
}
/**
* reads ejb annotations like {@link Column} and {@link JoinColumn}.
*
* @param attr attribute
* @return name of column
*/
public static String getColumnName(BeanAttribute attr) {
final Column c = attr.getAnnotation(Column.class);
if (c != null) {
return c.name();
}
final JoinColumn jc = attr.getAnnotation(JoinColumn.class);
if (jc != null) {
return jc.name();
}
return attr.getName();
}
/**
* if the first bean has non null value of type string, the second value must have the same value. will later be
* used to create a min/max range.
*
*
* e.g.: firstBean.myStrValue = 'Sch' and secondBean.myStrValue = null
* ==> secondBean.myStrValue = 'Sch'
* ==> query: ...between 'sch0000000' and 'schzzzzzzz'
*
*
* @param bean type
* @param firstBean min range
* @param secondBean max range
*/
public static void prepareStringValuesForBetween(T firstBean, T secondBean) {
final Class> clazz = firstBean.getClass();
final BeanClass bclazz = BeanClass.getBeanClass(clazz);
final Collection attributes = bclazz.getSingleValueAttributes();
for (final BeanAttribute beanAttribute : attributes) {
if (String.class.isAssignableFrom(beanAttribute.getType())) {
final String v1 = (String) beanAttribute.getValue(firstBean);
if (v1 != null) {
final String v2 = (String) beanAttribute.getValue(secondBean);
if (v2 == null) {
beanAttribute.setValue(secondBean, v1);
}
}
}
}
}
// /**
// * fills all attributes having no value to a defined min or max value.
// *
// * @param bean bean to change
// * @param maxValues if true, maximum values will be filled
// * @param useDatabaseFormat if true, the date will have a database format, the min numbers will be 0 and strings
// * will be surrounded by "'".
// */
// public static void fillNullValues(Object bean, boolean maxValues, boolean useDatabaseFormat) {
// final List extends IAttribute> singleValueAttributes =
// BeanClass.getBeanClass(bean.getClass()).getSingleValueAttributes();
// for (final IAttribute beanAttribute : singleValueAttributes) {
// if (beanAttribute.getValue(bean) != null) {
// continue;
// }
// if (BigDecimal.class.isAssignableFrom(beanAttribute.getType())) {
// if (maxValues) {
// beanAttribute.setValue(bean, new BigDecimal(Integer.MAX_VALUE));
// } else {
// beanAttribute.setValue(bean, new BigDecimal(Integer.MIN_VALUE));
// }
// } else if (Number.class.isAssignableFrom(beanAttribute.getType())) {
// String fieldName;
// if (maxValues) {
// fieldName = STR_MAX_VALUE;
// } else {
// fieldName = STR_MIN_VALUE;
// }
// Object newValue;
// try {
// /*if (useDatabaseFormat && !maxValues) {
// newValue = 0;
// } else*/{
// newValue = beanAttribute.getType().getField(fieldName).get(null);
// }
// } catch (final Exception e) {
// ManagedException.forward(e);
// return;
// }
// beanAttribute.setValue(bean, newValue);
// } else {//String or Date
// if (Date.class.isAssignableFrom(beanAttribute.getType())) {
// if (useDatabaseFormat) {
// //TODO: static dates use ORACLE specific format. use SQL-92
// final Date dbDateValue = new Date((maxValues ? MAXTIME : MINTIME)) {
// private static final long serialVersionUID = 1L;
// private final String pattern = "yyyy-MM-dd";
// private final/*static final */DateFormat sdf = new SimpleDateFormat(pattern);
//
// @Override
// public String toString() {
//// return "to_date('" + sdf.format(this) + "','" + pattern + "')";
// return "'" + sdf.format(this) + "'";
// }
// };
// beanAttribute.setValue(bean, dbDateValue);
// } else {
// beanAttribute.setValue(bean, maxValues ? new Date(MAXTIME) : new Date(MINTIME));
// }
// } else if (String.class.isAssignableFrom(beanAttribute.getType())) {
// final String prefix = "";//useDatabaseFormat ? "'" : "";
// final String postfix = "";//useDatabaseFormat ? "'" : "";
// //TODO: evaluate length through JPA annotation
// beanAttribute.setValue(bean, maxValues ? prefix + ""/*StringUtil.fixString("", 25, 'z', true)*/
// + postfix : prefix + ""/*StringUtil.fixString("", 25, '0', true)*/+ postfix);
// }
// }
// }
// }
// /**
// * WORKAROUND: TopLink is not able to insert a list of values to a query
// *
// * @param qstr ejb ql string ending with 'IN' , but without starting bracket.
// * @param parameter parameter to insert
// * @return query
// */
// public static Query setCollectionParameter(EntityManager entityManager, String qstr, Collection> parameter) {
// assert parameter != null && parameter.size() > 0 : "parameters must contain at least one item";
// final String colName = "colpar";
// final String colPar = ":" + colName;
// final StringBuffer qstrBuf = new StringBuffer(qstr + " (");
// int i = 0;
// for (final Object par : parameter) {
// qstrBuf.append((i > 0 ? "," : "") + colPar + ++i);
// }
// qstr = qstrBuf.toString() + ")";
// Query query = entityManager.createQuery(qstr);
// i = 0;
// for (final Object par : parameter) {
// query = query.setParameter(colName + ++i, par);
// }
// return query;
// }
//
// /**
// * Workaround helper for statements with 'in(...)'. The jpa-implementor may not be able to replace placeholder with
// * a collection of values.
// *
// * Use-Case: select .....and beanvar in (?x) <-- Collection with parameter --> select .....and beanvar in ('mypar1',
// * 'mypar2', ...)
// *
// * @param qstr origin query
// * @param matchExpression parameter name or '?' followed by a number (must exist in qstr)
// * @param parameter values to be inserted as comma-separated strings
// * @return qstr with filled values of parameter
// */
// public static final String getCollectionParameter(String qstr, String matchExpression, Collection> parameter) {
// StringBuilder qstrb = new StringBuilder(qstr);
// StringUtil.replace(qstrb,
// matchExpression,
// "'" + StringUtil.concat(new char[] { '\'', ',', '\'' }, parameter.toArray(new String[0])) + "'");
// return qstrb.toString();
// }
public static final Object getLogInfo(StringBuffer qStr, Collection parameter) {
return "\n" + qStr + "\n parameter: " + parameter;
}
/**
* checks whether to use {@link #setNamedParameters(Query, Object...)} or {@link #setParameters(Query, Object...)}.
*
* @param query query string to check
* @return true, if query contains standardized name parameters like :par1.
*/
public static final boolean useNamedParameters(String query) {
return !query.contains("?") || query.matches("\\s+[:]\\w+\\s+");
}
/**
* assigns the given args to the given query - using parameters without names (placeholder: ? or ?digit). see
* {@link #setNamedParameters(Query, Object...)}.
*
* @param query query to set the parameters for
* @param args parameters
* @return query holding all given parameters
*/
public static Query setParameters(Query query, Object... args) {
if (args != null) {
for (int i = 0; i < args.length; i++) {
//parameters are 1-based!
query = query.setParameter(i + 1, args[i]);
}
}
return query;
}
/**
* assigns the given args to the given query - using parameters with standardized names (par1, par2 etc.).
*
* @param query query to set the parameters for
* @param args parameters
* @return query holding all given parameters
*/
public static Query setNamedParameters(Query query, Object... args) {
if (args != null) {
for (int i = 0; i < args.length; i++) {
query = query.setParameter("par" + (i + 1), args[i]);
}
}
return query;
}
/**
* setHints
*
* @param query to set hints for
* @param hints (optional) hints to set
* @return changed query
*/
public static Query setHints(Query query, Map hints) {
if (hints != null) {
Set keySet = hints.keySet();
for (String hint : keySet) {
query = query.setHint(hint, hints.get(hint));
}
}
return query;
}
/**
* addMaxRowCountToQuery
*
* @param originQuery query where to add the maxresult statement
* @param maxresult maximum row count of query result
* @return
*/
public static String addMaxRowCountToQuery(String originQuery, int maxresult) {
return "select * from (" + originQuery + ") where rownum <= " + maxresult;
}
/**
* addOrderBy
* @param columns map of columns and their information, if order is descending.
* f.e.: Key="Name" and Value=true ==> "order by Name DESC"
* @return
*/
public static String addOrderBy(List columns) {
if (columns == null)
return "";
StringBuilder orderBy = new StringBuilder(" order by ");
for (String c : columns) {
String desc = c.startsWith("-") ? " DESC" : "";
int s = desc.length() > 0 || c.startsWith("+") ? 1 : 0;
orderBy.append(c.substring(s) + desc + ", ");
}
if (orderBy.length() > 1) //remove the last ", "
orderBy.setLength(orderBy.length() - 2);
return orderBy.toString();
}
// /**
// * recursive method to find all occurrences of attributes annotated with 'annotation' having a value that equals
// * 'value'.
// *
// * @param bean bean to be searched through all it's attributes
// * @param packagePrefix to filter classes to be checked
// * @param annotation annotation type
// * @param annotationValue can be null to search for null values
// * @param match (optional)
// * @param checkedInstances (optional)
// * @return all matches
// */
// public static Collection findAnnotationInEntityTree(Object bean,
// String packagePrefix,
// Class extends Annotation> annotation,
// Object annotationValue,
// Collection match,
// Collection checkedInstances) {
// if (bean == null) {
// return match;
// }
// if (checkedInstances == null) {
// checkedInstances = new HashSet();
// }
// if (match == null) {
// match = new HashSet();
// }
// if (bean instanceof Collection) {
// //loop over oneToMany collection ignoring lazyinit-exceptions
// try {
// Collection oneToMany = (Collection) bean;
// for (Object b : oneToMany) {
// findAnnotationInEntityTree(b, packagePrefix, annotation, annotationValue, match, checkedInstances);
// return match;
// }
// } catch (Exception ex) {
// LOG.debug(ex);
// return match;
// }
// }
// if (checkedInstances.contains(bean)) {
// return match;
// }
// if (!bean.getClass().getPackage().getName().startsWith(packagePrefix)) {
// return match;
// }
// LOG.debug("checking instance: " + bean);
// BeanClass> beanClass = BeanClass.getBeanClass(bean.getClass());
// Collection ids = beanClass.findAttributes(annotation);
// if (ids != null && ids.size() > 0) {
// if (ids.iterator().next().getValue(bean) == annotationValue
// || (annotationValue != null && annotationValue.equals(ids.iterator()
// .next()))) {
// LOG.info("matched value on bean: " + bean);
// match.add(bean);
// }
// }
// checkedInstances.add(bean);
// for (IAttribute> attr : beanClass.getAttributes()) {
// findAnnotationInEntityTree(attr.getValue(bean),
// packagePrefix,
// annotation,
// annotationValue,
// match,
// checkedInstances);
// }
// LOG.info("found matches for annotation " + annotation
// + " with value "
// + annotationValue
// + "\n"
// + StringUtil.toFormattedString(match, 200, true));
// return match;
// }
//
// /**
// * see {@link #useNewInstances(Object, List, List)}
// *
// * @param tree entity tree to walk through
// * @param newInstances new entity instances to be used
// * @return count of changes
// */
// public static int useNewInstances(Object tree, Object... newInstances) {
// List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy