/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package framework.beans;
import framework.audit.AuditDetails;
import framework.audit.AuditDoc;
import framework.beans.security.SecurityInterface;
import framework.generic.ClipsServerException;
import framework.utils.Converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Collection;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.jdom.JDOMException;
import reportgen.cores.ejb.annotations.DefineQueryEntity;
/**
*
* @author antony
*/
public class FindEntity {
@PersistenceContext
protected EntityManager manager;
public FindEntity() {
}
public FindEntity(EntityManager manager) {
this.manager = manager;
}
/**
* Возвращает имя сущности, читабельное для человека
* @param c класс сущности
* @return строка - имя сущности или "Unknown", если имя сущности неизвестно
*/
@SuppressWarnings("unchecked")
public static String getEntityHumanName(Class c) {
String res = null;
if (c.isAnnotationPresent(DefineQueryEntity.class)) {
DefineQueryEntity q = (DefineQueryEntity) c.getAnnotation(DefineQueryEntity.class);
res = q.title();
}
if(res != null) {
return res;
}
return c.getSimpleName();
}
protected enum OperatorType{
Binary,
Suffix,
Collection,
}
public class Field {
protected final static int FIELD_MAX_OPERATOR = 1000;
protected final static int FIELD_RECURSIVE_OPERATORS_BEGIN = FIELD_MAX_OPERATOR;
protected final static int FIELD_IN_SELLECT_OPERATORS_BEGIN = FIELD_RECURSIVE_OPERATORS_BEGIN + FIELD_MAX_OPERATOR;
public final static int OPERATOR_EQUAL = 1;
public final static int OPERATOR_NOT_EQUAL = 2;
public final static int OPERATOR_MORE = 3;
public final static int OPERATOR_LESS = 4;
public final static int OPERATOR_EQUAL_OR_MORE = 5;
public final static int OPERATOR_EQUAL_OR_LESS = 6;
public final static int OPERATOR_IN = 7;
public final static int OPERATOR_NOT_IN = 8;
public final static int OPERATOR_LIKE = 9;
public final static int OPERATOR_NOT_LIKE = 10;
public final static int OPERATOR_NOT_NULL = 11;
public final static int OPERATOR_IS_NULL = 12;
protected final String field;
protected final Object value;
protected int operator = OPERATOR_EQUAL;
protected String paramPrefix;
public Field(String field, Object value) {
this.field = field;
this.value = value;
}
public Field(String field, Object value, int operator) {
if (operator > FIELD_MAX_OPERATOR || operator <= 0){
throw new IllegalArgumentException("operator not mach field class");
}
this.field = field;
this.value = value;
this.operator = operator;
}
protected String operator() {
switch (operator) {
case OPERATOR_EQUAL:
return "=";
case OPERATOR_NOT_EQUAL:
return "<>";
case OPERATOR_MORE:
return ">";
case OPERATOR_LESS:
return "<";
case OPERATOR_EQUAL_OR_MORE:
return ">=";
case OPERATOR_EQUAL_OR_LESS:
return "<=";
case OPERATOR_IN:
return " IN ";
case OPERATOR_NOT_IN:
return " NOT IN ";
case OPERATOR_LIKE:
return " LIKE ";
case OPERATOR_NOT_LIKE:
return " NOT LIKE ";
case OPERATOR_NOT_NULL:
return " is not null ";
case OPERATOR_IS_NULL:
return " is null ";
default:
throw new IllegalStateException();
}
}
protected OperatorType getOperatorType(){
switch (operator) {
case OPERATOR_EQUAL:
case OPERATOR_NOT_EQUAL:
case OPERATOR_MORE:
case OPERATOR_LESS:
case OPERATOR_EQUAL_OR_MORE:
case OPERATOR_EQUAL_OR_LESS:
case OPERATOR_LIKE:
case OPERATOR_NOT_LIKE:
return OperatorType.Binary;
case OPERATOR_IN:
case OPERATOR_NOT_IN:
return OperatorType.Collection;
case OPERATOR_NOT_NULL:
case OPERATOR_IS_NULL:
return OperatorType.Suffix;
default:
throw new IllegalStateException();
}
}
protected String toSQL(String entityAliase, String superEntityAliase, String paramPrefix){
this.paramPrefix = paramPrefix;
StringBuilder target = new StringBuilder();
switch (getOperatorType()){
case Binary:
if (value instanceof Collection){
throw new UnsupportedOperationException("Not supported in this version");
}
target.append(entityAliase);
target.append('.');
target.append(field);
target.append(operator());
target.append(':');
target.append(paramPrefix);
break;
case Suffix:
target.append(entityAliase);
target.append('.');
target.append(field);
target.append(operator());
break;
case Collection:
if (!(value instanceof Collection) && null != value){
throw new IllegalStateException("field " + field + " must be collection");
}
int len = (null == value? 0: ((Collection)value).size());
if (0 == len){
switch (operator){
case OPERATOR_IN:
return "1 = 2";// always false
case OPERATOR_NOT_IN:
return "1 = 1";// always true
}
}
else{
target.append(entityAliase);
target.append('.');
target.append(field);
target.append(operator());
target.append('(');
int i;
for (i = 0; i < len - 1; i++){
target.append(':');
target.append(paramPrefix);
target.append('_');
target.append(i);
target.append(", ");
}
target.append(':');
target.append(paramPrefix);
target.append('_');
target.append(i);
target.append(')');
}
break;
default:
throw new IllegalStateException();
}
return target.toString();
}
protected void setParametres(Query query){
switch (getOperatorType()){
case Binary:
query.setParameter(paramPrefix, value);
break;
case Suffix:
break;
case Collection:
Collection col = (Collection)value;
if (col != null && 0 < col.size()){
int i = 0;
for (Object val : col) {
query.setParameter(paramPrefix + '_' + i, val);
i++;
}
}
break;
default:
throw new IllegalStateException();
}
}
}
public abstract class FieldRecursive extends Field{
public final static int OPERATOR_OR = 1 + FIELD_RECURSIVE_OPERATORS_BEGIN;
public final static int OPERATOR_AND = 2 + FIELD_RECURSIVE_OPERATORS_BEGIN;
protected ArrayList<Field> fields = new ArrayList<Field>();
public FieldRecursive(String field, Object value, int operator) {
super(field, value);
if ((operator != OPERATOR_OR || operator != OPERATOR_AND) && operator >= 0) {
throw new IllegalArgumentException();
}
this.operator = operator;
}
public void add(Field f){
fields.add(f);
}
@Override
protected String toSQL(String entityAliase, String superEntityAliase, String paramPrefix) {
switch (operator){
case OPERATOR_OR:
return makeFeldSql(entityAliase, superEntityAliase, paramPrefix, " or ", fields);
case OPERATOR_AND:
return makeFeldSql(entityAliase, superEntityAliase, paramPrefix, " and ", fields);
default:
throw new RuntimeException();
}
}
@Override
protected void setParametres(Query query){
for (Field cur : fields) {
cur.setParametres(query);
}
}
}
public class FieldInSellect extends FieldRecursive{
public final static int OPERATOR_IN_SELLECT = 3 + FIELD_RECURSIVE_OPERATORS_BEGIN;
public final static int OPERATOR_NOT_IN_SELLECT = 4 + FIELD_RECURSIVE_OPERATORS_BEGIN;
protected final String what;
protected final Class<? extends GenericEntity> enityClass;
public FieldInSellect(String field, String what, Class<? extends GenericEntity> enityClass, int operator) {
super(field, null, -1);
if (OPERATOR_IN_SELLECT != operator && OPERATOR_NOT_IN_SELLECT != operator){
throw new IllegalArgumentException();
}
this.operator = operator;
this.what = what;
this.enityClass = enityClass;
}
@Override
protected String toSQL(String classAliase, String superClassAliase, String paramPrefix) {
StringBuilder target = new StringBuilder();
target.append(classAliase);
target.append('.');
target.append(field);
switch (operator){
case OPERATOR_IN_SELLECT:
target.append(" IN (");
break;
case OPERATOR_NOT_IN_SELLECT:
target.append(" NOT IN (");
break;
default:
throw new IllegalStateException();
}
target.append(makeFeldSelect(SelectType.select,
what, enityClass,
superClassAliase, paramPrefix,
fields, null));
target.append(')');
return target.toString();
}
}
protected <T extends GenericEntity> T findEntity(Class <T> entityClass, int id, String entityName) throws ClipsServerException {
@SuppressWarnings("unchecked")
T entity = manager.find(entityClass, id);
if (entity == null) {
throw new ClipsServerException("Отсутствует запись в таблице " + entityName + ", id:" + id);
}
return entity;
}
protected <T extends GenericEntity> T findEntity(Class <T> entityClass, int id)
throws ClipsServerException {
@SuppressWarnings("unchecked")
T entity = manager.find(entityClass, id);
if (entity == null) {
throw new ClipsServerException("Отсутствует запись в таблице " +
getEntityHumanName(entityClass) + ", id:" + id);
}
return entity;
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass, String field, Object value, String extraSql) {
Field[] f = {new Field(field, value)};
return findEntityWhat(null, entityClass, f, extraSql);
}
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass, String field, Object value) {
Field[] f = {new Field(field, value)};
return findEntityList(entityClass, f);
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass) {
return findEntityWhatWithResCount(null, entityClass, new ArrayList<Field>(0), "", -1);
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass, Field[] fields) {
return findEntityWhat(null, entityClass, fields, "");
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass, List<Field> fields) {
return findEntityWhatWithResCount(null, entityClass, fields, "", -1);
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass, Field[] fields, String extraSql) {
return findEntityWhat(null, entityClass, fields, extraSql);
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityList(Class <T> entityClass, List<Field> fields, String extraSql) {
return findEntityWhatWithResCount(null, entityClass, fields, extraSql, -1);
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityListWithResCount(Class <T> entityClass, Field[] fields, String extraSql, int resCount) {
return findEntityWhatWithResCount(null, entityClass, fields, extraSql, resCount);
}
@SuppressWarnings("unchecked")
protected <T extends BaseEntity> List<T> findEntityListWithResCount(Class <T> entityClass, List<Field> fields, String extraSql, int resCount) {
return findEntityWhatWithResCount(null, entityClass, fields, extraSql, resCount);
}
protected <T extends BaseEntity> int getEntityCount(Class <T> entityClass, Field[] fields) {
return getEntityCount(entityClass, fields, "");
}
protected <T extends BaseEntity> int getEntityCount(Class <T> entityClass, List<Field> fields) {
return getEntityCount(entityClass, fields, "");
}
protected <T extends BaseEntity> int getEntityCount(Class<T> entityClass, Field[] fields, String extraSql) {
List<Field> list = (null == fields? new ArrayList<Field>(0): Arrays.asList(fields));
return getEntityCount(entityClass, list, extraSql);
}
protected <T extends BaseEntity> int getEntityCount(Class<T> entityClass, List<Field> fields, String extraSql) {
Iterator c = findEntityWhatWithResCount("count(a)", entityClass, fields, extraSql, -1).iterator();
Object obj = c.next();
Long b = (Long) (obj);
return b.intValue();
}
/**
* Вызвать оператор SELECT what где все указанные поля будут удовлетворять опред. условиям
* @param <T>
* @param what - что требуется выбрать, если = null, то будет заменено на "a" - сущность используемая в запросе
* @param entityClass
* @param fields
* @param extraSql
* @return
*/
protected <T extends BaseEntity> List findEntityWhat(String what, Class<T> entityClass, Field[] fields, String extraSql) {
return findEntityWhatWithResCount(what, entityClass, fields, extraSql, -1);
}
protected <T extends BaseEntity> List findEntityWhatWithResCount(String what, Class<T> entityClass, Field[] fields, String extraSql, int resCount) {
List<Field> list = (null == fields? new ArrayList<Field>(0): Arrays.asList(fields));
return findEntityWhatWithResCount(what, entityClass, list, extraSql, resCount);
}
protected <T extends BaseEntity> List findEntityWhatWithResCount(String what, Class<T> entityClass, List<Field> fields, String extraSql, int resCount) {
String sql = makeFeldSelect(SelectType.select, what, entityClass, null, null, fields, extraSql);
// System.out.println("sql debug " + sql);
Query query = manager.createQuery(sql);
setFieldsParamiters(query, fields);
if (resCount >= 0) {
query.setMaxResults(resCount);
}
List target = query.getResultList();
return target;
}
/**
* Нужно использовать удаление с аудитом - реализовано в SecuredBean
* @param <T>
* @param entityClass
* @param fields
* @throws ClipsServerException
* @deprecated
*/
@Deprecated
protected <T extends BaseEntity> void deleteEntityList(Class<T> entityClass, Field[] fields) throws ClipsServerException {
try {
List<Field> list = (null == fields? new ArrayList<Field>(0): Arrays.asList(fields));
String sql = makeFeldSelect(SelectType.remove, null, entityClass, null, null, list, null);
// System.out.println("sql debug " + sql);
Query query = manager.createQuery(sql);
setFieldsParamiters(query, list);
query.executeUpdate();
}
catch (Exception ex) {
throw new ClipsServerException("Попытка удаления не удалась: ", ex);
}
}
private static String makeFeldSql(
String entityAliase, String superEntityAliase,
String paramPrefix, String fieldSeparator,
List<Field> fieldList){
if (fieldList == null){
return "";
}
StringBuilder target = new StringBuilder();
int fieldCount = 0;
boolean fistField = true;
for (Field field : fieldList) {
if (fistField){
fistField = false;
}
else{
target.append(fieldSeparator);
}
target.append('(');
target.append(field.toSQL(entityAliase, superEntityAliase, paramPrefix + '_' + fieldCount++));
target.append(')');
}
return target.toString();
}
protected static void setFieldsParamiters(Query query, List<Field> fieldList){
for (Field field : fieldList) {
field.setParametres(query);
}
}
public static final String ENTITY_ALIASE_BASE = "a";
public static final String ENTITY_ALIASE_SUBQERY_SUFIX = "_sub";
public static final String PARAM_BASE_NAME = "param";
protected enum SelectType{
select,
remove,
}
protected static <T extends BaseEntity> String makeFeldSelect(SelectType type, String what, Class<T> entityClass, String superEntityAliase, String paramPrefix, List<Field> fieldList, String extraSQL){
String entytyAliase = paramPrefix == null? ENTITY_ALIASE_BASE: paramPrefix + ENTITY_ALIASE_SUBQERY_SUFIX;
String paramName = paramPrefix == null? PARAM_BASE_NAME: entytyAliase;
StringBuilder target = new StringBuilder();
switch (type){
case select:
target.append("SELECT ");
if (null == what){
target.append(entytyAliase);
}
else{
if (null != paramPrefix){
target.append(entytyAliase);
target.append('.');
}
target.append(what);
}
break;
case remove:
target.append("DELETE ");
break;
}
target.append(" FROM ");
target.append(entityClass.getSimpleName());
target.append(" AS ");
target.append(entytyAliase);
String subSql = makeFeldSql(entytyAliase, superEntityAliase, paramName, " AND ", fieldList);
if (!subSql.trim().isEmpty()){
target.append(" WHERE (");
target.append(subSql);
target.append(")");
}
if (extraSQL != null){
target.append(extraSQL);
}
return target.toString();
}
protected <T extends SecurityInterface> T getBean(Class<T> clazz, int sessionID) throws ClipsServerException {
String name = "clips-beans/"+clazz.getSimpleName();
try {
Context c = new InitialContext();
@SuppressWarnings("unchecked")
T bean = (T) c.lookup(name);
bean.setSession(sessionID);
return bean;
} catch (NamingException ne) {
throw new ClipsServerException("Не удалось получить сервис " + name, ne);
}
}
protected void checkXML(String xml) throws ClipsServerException {
try {
Converter.stringToXml(xml);
} catch (JDOMException ex) {
throw new ClipsServerException("Некорректный формат данных");
}
}
protected int saveEntity(GenericEntity entity) {
int id = entity.getId();
if(id != 0) {
entity = manager.merge(entity);
} else {
manager.persist(entity);
manager.flush();
manager.refresh(entity);
id = entity.getId();
}
return id;
}
protected void removeEntity(BaseEntity entity) {
manager.remove(entity);
}
/**
* Возвращает истину если сущность соответствует ID
* @param entity может быть null
* @param id может быть 0
* @return
*/
static public boolean isEntityEqualID (GenericEntity entity, int id) {
return entity == null && id == 0
|| entity != null && entity.getId() == id;
}
/**
* проверяет равны ли два объекта, с помощью функции equal (с проверкой на null)
* @param <T>
* @param v1
* @param v2
* @return
*/
static public <T> boolean nullEqual(T v1, T v2){
return v1 == v2 || (v1 != null && v1.equals(v2));
}
}